我是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中有一些类似的问题,但是它们似乎都没有向我解释这个问题。
答案 0 :(得分:8)
username
是String
,但promptUsername
是IO String
。您需要执行以下操作:
username <- promptUsername
let entry = Entry username "somepassword"
persist entry
答案 1 :(得分: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
是操作而不是字符串。动作'返回一个字符串',因此它具有类型IO String
,但它本身就像一个字符串。由于Entry x y
在x位置需要String
,因此动作形状的某些东西不能比数字或布尔值更合适。因此,在定义复杂动作main
时,必须“提取”在任何执行情况下由更简单的动作promptUsername
产生的字符串,并将String
作为第一个参数入口。然后,对结果persist
Entry
操作