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

How to wrap char literal in IO monad in Haskell?

我知道您应该将要对结果执行的操作包装在 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。

错误信息:

[1 of 2] Compiling Lib              ( /Users/jamesstrieter/hask-tink/src/Lib.hs, interpreted )

/Users/jamesstrieter/hask-tink/src/Lib.hs:66:18: error:
    • Couldn't match expected type ‘IO char’ with actual type ‘Char’
    • In the second argument of ‘(==)’, namely ‘'q'’
      In the expression: x == 'q'
      In an equation for ‘what2do’: what2do x = x == 'q'
    • Relevant bindings include
        x :: IO char
          (bound at /Users/jamesstrieter/hask-tink/src/Lib.hs:66:9)
        what2do :: IO char -> Bool
          (bound at /Users/jamesstrieter/hask-tink/src/Lib.hs:66:1)
   |
66 | what2do x = x == 'q'
   |                  ^^^
Failed, no modules loaded.

But you can't compare a char literal to an IO Char directly.

当然可以,但是当您 "bind" IO 操作的结果时,它不再是 IO Char,而是 Char,这就是它起作用的原因。

更多的话:

Prelude> :t getChar
getChar :: IO Char
Prelude> c <- getChar
x
Prelude> :t c
c :: Char

您发布的代码看起来完全正确且功能正常。

do-notation 是在 monad 中处理值的一种方式。

do 块中的

c <- getChar 将 c 绑定到 IO Char 中的字符,您使用 getChar 获得。你可以在这里比较 c == 'q' 就好了,因为 c 是一个普通的字符,而不是 IO Char

为了直接回答你的问题,你可以使用 return 函数将纯值放入任何 monad,包括 IO,所以 return 'q' "wraps" 字符文字 'q' 变成一个单子。在这种情况下,这不是您想要的,您已经拥有的代码正是您要寻找的。

关于 IO monad 最重要的事情之一是表达式 m >>= f 执行操作 m ,它也不会调用函数 f.

相反,它只是创建了一个 new IO 动作来包裹 mfwhich,执行时,最后会执行m,提取return值,然后用该值调用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")

你实际上是在说“构建一个包含 getCharIO 动作和一个 Char -> IO () 类型的函数,这样当这个动作被执行时,它会执行 getChar 并将生成的 Char 传递给函数以生成 另一个 IO 立即执行的操作。"