我是Haskell的新手,并使用do表示法通过Either验证用户的选择。
userChoice :: String -> Either String String
userChoice option
| option == "1" = Right "You proceed with option 1."
| option == "2" = Right "You proceed with option 2"
| option == "3" = Right "You proceed with option 3"
| option == "4" = Right "You proceed with option 4"
| otherwise = Left $ "\n\nInvalid Option...\nWhat would you like to do?\n" ++ displayOptions(0)
displayOptions :: Int -> String
displayOptions option
| option == 0 = "1 - Option 1\n2 - Option 2\n3 - Option 3\n4 - Option 4"
| otherwise = "invalid"
main = do
putStrLn "Welcome."
let start startMessage = do
putStrLn startMessage
let ask message = do
putStrLn message
choice <- getLine
either ask ask $ userChoice(choice)
ask $ "What would you like to do?\n" ++ displayOptions(0)
start "Choose a number between 1-4."
这可以正常工作,但是在用户选择正确的选项后,我想继续进行程序的下一部分。我可以使用return,但是会丢失用户选择的选项。
作为一个例子,我可以在用户选择一项权利时将return放在此处,但是它不会说字符串“您继续选择...”。
main = do
putStrLn "Welcome."
let start startMessage = do
putStrLn startMessage
let ask message = do
putStrLn message
choice <- getLine
either ask return $ userChoice(choice)
ask $ "What would you like to do?\n" ++ displayOptions(0)
start "Choose a number between 1-4."
-- putStrLn userChoice2(choice)
let continue continueMessage = do
putStrLn continueMessage
let ask message = do
putStrLn message
choice <- getLine
either continue continue $ userChoice(choice)
ask $ "What would you like to do?"
continue "We are now here..."
如果我尝试将continue作为正确的选项,则会引发范围错误。同样,如果我使用return并尝试为userChoice创建原始的克隆函数,那么我将无法再访问作用域选择。
userChoice2 :: String -> String
userChoice2 option
| option == "1" = "You proceed with option 1."
| option == "2" = "You proceed with option 2"
| option == "3" = "You proceed with option 3"
| option == "4" = "You proceed with option 4"
| otherwise = "\n\nInvalid Option...\nWhat would you like to do?\n" ++ displayOptions(0)
有没有办法将它们优雅地链接在一起?
答案 0 :(得分:2)
听起来您只需要绑定start
的monad中返回的值,就像这样:
main = do
putStrLn "Welcome."
let start startMessage = do
putStrLn startMessage
let ask message = do
putStrLn message
choice <- getLine
either ask return $ userChoice(choice)
ask $ "What would you like to do?\n" ++ displayOptions(0)
-- THE NEW BIT I ADDED:
opt <- start "Choose a number between 1-4."
putStrLn opt -- THIS PRINTS "You proceed with ..."
-- SNIP
您可以阅读有关“将符号do
删除”的信息,以了解其如何转换为lambda和Monad
类的方法(>>=
和return
)。
其他一些建议:
您可以使用(并且应该更喜欢)模式匹配来代替警卫和==
(Eq
类的一种方法,并非所有类型都可以实现)。例如
userChoice2 option = case option of
"1" -> "You proceed with option 1."
"2" -> "You proceed with option 2"
请记住,在haskell中,在foo
和a
上调用b
的语法是foo a b
而不是foo(a,b)
打开警告(在您学习和基于生产代码的基础上)可能非常有帮助,例如在这里,我打开-Wall
后会在ghci中加载您的文件:
Prelude> :set -Wall
Prelude> :l k.hs
[1 of 1] Compiling Main ( k.hs, interpreted )
k.hs:15:1: warning: [-Wmissing-signatures]
Top-level binding with no type signature: main :: IO b
|
15 | main = do
| ^^^^
k.hs:24:5: warning: [-Wunused-do-bind]
A do-notation statement discarded a result of type ‘String’
Suppress this warning by saying
‘_ <- start "Choose a number between 1-4."’
|
24 | start "Choose a number between 1-4."
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Ok, one module loaded.
请注意,它警告您start
返回IO String
,但是您对String
的值没有做任何事情,这确实是一个错误。如果您确实要舍弃该值,则可以使用void
将该值明确显示并消除错误。