2017-04-02 78 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一樣工作。如果類型化字符不在列表中,我想將它放入現有列表中,但如果字符已存在於此列表中,則不會添加它,並且該列表中的所有實例都將從列表中刪除。稍後再研究一下,我會馬上提出另一個問題。 –

相關問題