我知道您应该将要对结果执行的操作包装在monad中,而不是从monad中解包。
我找不到如何做到这一点的任何对白痴友好的例子。
例如,我想做这样的事情:
myFunction = do
c <- getChar
if (c == 'q')
then putStrLn "take action 1"
else putStrLn "take action 2"
但是您不能直接将char文字与IO Char进行比较。
GHCi版本是8.4.4。
错误消息:
[2之1]编译Lib(/Users/jamesstrieter/hask-tink/src/Lib.hs,已解释)
/Users/jamesstrieter/hask-tink/src/Lib.hs:66:18:错误: •无法将预期类型“ IO char”与实际类型“ Char”匹配 •在“(==)”的第二个参数中,即“'q'” 在表达式中:x =='q' 在“ what2do”的等式中:what2do x = x =='q' •相关绑定包括 x :: IO字符 (绑定在/Users/jamesstrieter/hask-tink/src/Lib.hs:66:9) what2do :: IO字符-> Bool (绑定在/Users/jamesstrieter/hask-tink/src/Lib.hs:66:1) | 66 | what2do x = x =='q' | ^^^ 失败,未加载任何模块。
答案 0 :(得分:7)
您发布的代码看起来非常正确且功能正常。
do-notation是在monad中使用值的一种方法。
do块中的 c <- getChar
将c绑定到通过IO Char
获得的getChar
中的char。您可以在这里比较c == 'q'
很好,因为c是一个普通字符,而不是IO Char
。
要回答您的直接问题,可以使用return
函数将纯值放入包括IO在内的任何monad中,因此return 'q'
将字符文字“ q”“包装”到monad中。在这种情况下,这不是您想要的,已经在寻找的代码就是您想要的。
答案 1 :(得分:4)
但是您不能直接将char文字与IO Char进行比较。
当然可以,但是当您“绑定” IO操作的结果时,它不再是IO Char
,而只是Char
,这就是它起作用的原因。
换句话说:
Prelude> :t getChar
getChar :: IO Char
Prelude> c <- getChar
x
Prelude> :t c
c :: Char
答案 2 :(得分:1)
要了解有关IO
单子的最重要的事情之一是表达式m >>= f
不会执行动作m
,也不执行调用函数f
。
相反,它只是创建一个 new IO
操作,该操作包装了m
和f
,并在执行后最终执行m
,提取返回值,然后调用f
并返回结果。
就是这样。您整个Haskell程序不过是一个DSL,用于建立分配给main
的单个IO操作,Haskell runtime 将为您执行。
所以当你写
-- Rewritten slightly for brevity
myFunction = do
c <- getChar
putStrLn (if (c == 'q')
then "take action 1"
else "take action 2")
这是应接受的
myFunction = getChar >>= (\c -> putStrLn (if (c == 'q') then "take action 1" else "take action 2")
,您实际上是在说“构建包含IO
和类型getChar
的功能的Char -> IO ()
动作,这样当执行此动作时,它就会执行{{1} },并将生成的getChar
传递给函数,以产生另一个 Char
动作,并立即执行。”