以下是我目前的代码:
type Deck = [Card]
data Card = Card {question :: String, answer :: String} deriving (Show)
askForNextCommand deck = do
putStrLn "What would you like to do?"
userInput <- getLine
return userInput
loop :: Deck -> IO ()
loop deck = print $ askForNextCommand deck
main :: IO ()
main = loop []
我遇到的问题是askForNextCommand
功能。我希望能够在另一个函数中使用用户输入,如下所示:
有一副卡片,每个卡片都包含一个问题和答案,用户可以对它们进行测验,在列表中添加更多卡片,删除卡片等。
当我学习它时,我在Python中创建了一个类似的程序,所以我现在正尝试在Haskell中创建它。
我有另一个函数接受输入并根据输入的内容做一些事情:
doCommand command deck
| command == "add" = addFunc deck
| command == "remove" = removeFunc deck
| otherwise = doCommand (askForNextCommand deck) deck
问题是我无法弄清楚如何将命令参数作为用户输入。我希望askForNextCommand
提示用户然后将其输入作为字符串返回,但我现在已经搜索了大约半小时但找不到任何内容。我确定这是一个简单的修复,但我不知道在哪里看。任何帮助将不胜感激。
答案 0 :(得分:1)
首先,始终为您的顶层绑定提供类型签名。这将极大地帮助您解决类型错误。
askForNextCommand :: Deck -> IO String
askForNextCommand deck = do
putStrLn "What would you like to do?"
userInput <- getLine
return userInput
顺便说一句,最后两行是反模式。编写上述函数的标准方法是:
askForNextCommand :: Deck -> IO String
askForNextCommand deck = do
putStrLn "What would you like to do?"
getLine
到目前为止一切顺利。现在到了罪魁祸首:
loop :: Deck -> IO ()
loop deck = print $ askForNextCommand deck
此处askForNextCommand deck
的类型为IO String
(请参阅上一个签名)。
函数print
尝试将其转换为字符串(从技术上讲,转换为类型类Show
),
但为此,它需要一个不可能构建的函数show :: IO String -> String
。
实际上,IO String -> String
会神奇地转换与用户交互的一段代码,并在一段代码中产生刺痛(例如getLine
),从而产生没有用户交互的字符串。
以下是更正后的版本:
loop :: Deck -> IO ()
loop deck = do
cmd <- askForNextCommand deck
print cmd
或等同地
loop :: Deck -> IO ()
loop deck = askForNextCommand deck >>= print
上面运行IO,获取字符串,然后打印它。 print
现在收到String
,所以一切都很好。
拇指规则是:您可以使用x <- someIOValue
内的do
从IO monad中提取内容。问题是您只能在再次返回IO类型的函数中执行此操作。
如果你想了解更多关于Haskell的monads和朋友的信息,那就是优秀的博文 Functors, Applicatives, And Monads In Pictures在实践中解释了它们 轻量级的方式。
最后,上面的代码会添加一些额外的引号。使用putStrLn
代替print
是否要避免引用。