Haskell:"无法将预期类型IO()与IO ThreadId"匹配

时间:2017-04-02 13:07:06

标签: haskell concurrency io

我在Haskell中并发新手并且我试图获得一个结果,其中在main线程中创建了一个新的MVar,将其空转到userThread thread,从用户获取字符输入,然后将该值放入MVar并打开main线程。

这是我到目前为止所拥有的

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)

现在,我一直试图将输入的字符放入MVar,我已经粘贴了下面的错误

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 个答案:

答案 0 :(得分:2)

forkIO $ userThread chan是一个IO操作,返回ThreadId,并且是main do块中的最后一个语句,它使main返回。但是,您声明了main :: IO (),因此存在类型不匹配。

简单地返回一个虚拟元组。

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

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

答案 1 :(得分:2)

由于你在学习haskell时会一遍又一遍地得到这个错误,我想为你解压缩它:

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.