如何在Haskell的IO monad中包装char文字?

时间:2019-03-10 04:30:37

标签: haskell monads io-monad do-notation

我知道您应该将要对结果执行的操作包装在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'    | ^^^ 失败,未加载任何模块。

3 个答案:

答案 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操作,该操作包装了mf,并在执行后最终执行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动作,并立即执行。”