6

我是 Haskell 的新手,我尝试了解如何正确执行 IO。

以下工作正常:

main = do
  action <- cmdParser
  putStrLn "Username to add to the password manager:"
  username <- getLine
  case action of
    Add -> persist entry
      where
        entry = Entry username "somepassword"

而以下导致编译错误:

main = do
  action <- cmdParser
  case action of
    Add -> persist entry
      where
        entry = Entry promptUsername "somepassword"

promptUsername = do
  putStrLn "Username to add to the password manager:"
  username <- getLine

错误在这里:

Couldn't match expected type `IO b0' with actual type `[Char]'
Expected type: IO b0
  Actual type: String
In the expression: username
[...]

这里发生了什么?为什么第一个版本有效,而第二个版本无效?

我知道在 Stack Overflow 中有一些类似的问题,但似乎没有一个可以向我解释这个问题。

4

2 回答 2

9

username是一个String,但是promptUsername是一个IO String。您需要执行以下操作:

username <- promptUsername
let entry = Entry username "somepassword"
persist entry
于 2012-08-18T06:33:51.463 回答
0

这是另一个变体。

main = do
  action <- cmdParser
  case action of
    Add -> do username <- promptUsername
              let entry = Entry username "somepassword"
              persist entry

promptUsername :: IO String
promptUsername = do
  putStrLn "Username to add to the password manager:"
  getLine

-- fake definitions to make things compile

persist :: Entry ->  IO ()
persist = print

cmdParser :: IO Add
cmdParser = fmap (const Add) getLine

data Add = Add deriving Show
data Entry = Entry String String deriving Show

问题只是那promptUsername是一个动作而不是一个字符串。动作“返回一个字符串”,所以它有 type IO String,但它本身一点也不像一个字符串。由于在 x 位置Entry x y需要 a ,因此动作String形状的东西不能比数字或布尔值更适合那里。因此,在定义您的复杂操作时,您必须“提取”在任何执行情况下将由更简单操作产生的字符串,并将条目作为第一个参数。然后你对结果执行操作mainpromptUsernameStringpersistEntry

于 2012-08-18T12:09:03.570 回答