2017-04-02 62 views
1

我是新来的Haskell并发性,我试图得到一个结果,在main线程中创建一个新的MVar,通过清空userThread线程,该线程从用户处接收字符输入,然后将该值放入MVar中并使线程打印它。Haskell:“无法与IO ThreadId匹配预期类型IO()”

这里是我迄今为止

module Main where 

import Control.Concurrent 
import Control.Monad 
import System.IO 
import System.Random 
import Text.Printf 

data Msg = C Char | Time 


main :: IO() 
main = do 
    hSetBuffering stdout NoBuffering 
    hSetBuffering stdin NoBuffering 
    hSetEcho stdin False 

    -- shared resources 
    chan <- newEmptyMVar 
    forkIO $ userThread chan 
    --r <- takeMVar chan 
    --show(r) 


userThread :: MVar Msg -> IO() 
userThread chan = forever $ do 
    x <- getChar 
    putMVar chan (C x) 

现在,我卡在试图把输入的字符到无功,我已经粘贴了以下错误

assignment1.hs:20:3: error: 
    * Couldn't match type `ThreadId' with `()' 
     Expected type: IO() 
     Actual type: IO ThreadId 
    * In a stmt of a 'do' block: forkIO $ userThread chan 
     In the expression: 
     do { hSetBuffering stdout NoBuffering; 
      hSetBuffering stdin NoBuffering; 
      hSetEcho stdin False; 
      chan <- newEmptyMVar; 
      .... } 
     In an equation for `main': 
      main 
      = do { hSetBuffering stdout NoBuffering; 
        hSetBuffering stdin NoBuffering; 
        hSetEcho stdin False; 
        .... } 
Failed, modules loaded: none. 

任何指向正确方向的指针都将非常有帮助! 谢谢大家

回答

2

forkIO $ userThread chan是返回ThreadId一个IO动作,并且是在maindo块的最后一条语句,它使main回报为好。但是,您宣布main :: IO(),因此存在类型不匹配。

只需返回一个虚拟元组。

main = do 
    ... 
    forkIO $ userThread chan 
    return() 

(还有这一个void库函数,但是你可以忽略它。)

+1

谢谢,这有帮助。我现在可以使用'deriving(Show)'来编译和打印我的字符,但是,这个输出例如是'C'g'',我怎么才能打印出用户按下的字符? –

+1

@SebMarsh你可以定义你自己的'Show'实例,或者你可以定义一个函数'Msg-> String'或Msg-> Text',然而你喜欢打印一条消息(然后调用'putStrLn'将它写入标准输出) – jberryman

+0

再次感谢。正如我回复jberryman我想我可以使用这样的事情来获取我的消息数据像一个字符串,如果它是一个字符。我如何着手做这件事?我之前没有使用过自己的实例,所以我有点迷路。 –

2

既然你要过来,当你学习哈斯克尔在得到这个错误,我想将它解开为您提供:

assignment1.hs:20:3: error: 

GHC是给你的文件,行数和列数:file:line:col

* Couldn't match type `ThreadId' with `()' 
     Expected type: IO() 
     Actual type: IO ThreadId 

Expected type是指基于上下文例如GHC期待表达的类型。您提供的类型签名,或者您使用从该表达式返回的值的方式。 Actual type是表达式的实际类型,例如,文字'c'具有类型Charmap fst [('c', undefined)]具有实际类型[Char]

* In a stmt of a 'do' block: forkIO $ userThread chan 

这^是问题的陈述。 forkIO返回ThreadId(您可以从其类型签名中看到)。我想这里棘手的部分是知道为什么类型检查者期望类型为IO()(因为您的类型签名,并且在您的do块的最后一条语句中返回的值将是返回的类型,因为chi提到)。

这是非常有用的ghci开放,以帮助您回答这些问题与您正在开发:

Prelude> import Control.Concurrent 
Prelude Control.Concurrent> :t forkIO 
forkIO :: IO() -> IO ThreadId 
Prelude Control.Concurrent> :t() 
() ::() 
Prelude Control.Concurrent> :t repeat() 
repeat() :: [()] 

剩下的就是更多的情况下,你可能,如果你有在文件中的前不需要你:

 In the expression: 
     do { hSetBuffering stdout NoBuffering; 
      hSetBuffering stdin NoBuffering; 
      hSetEcho stdin False; 
      chan <- newEmptyMVar; 
      .... } 
     In an equation for `main': 
      main 
      = do { hSetBuffering stdout NoBuffering; 
        hSetBuffering stdin NoBuffering; 
        hSetEcho stdin False; 
        .... } 
Failed, modules loaded: none. 
+1

谢谢,这有助于我理解我的问题,但现在我面临着一个全新的问题,就是如何让我的Msg类型像String一样工作。如果类型化字符不在列表中,我想将它放入现有列表中,但如果字符已存在于此列表中,则不会添加它,并且该列表中的所有实例都将从列表中删除。稍后再研究一下,我会马上提出另一个问题。 –

相关问题