我想编写一个函数,该函数在被调用时将不停地询问用户输入,直到输入可以被读取为整数为止(此时,该整数将返回到可能的do块中,在该块中调用了该函数第一名)
我的代码在这里:
lp_reqInt =
do
input1 <- getLine
if ((readMaybe input1 :: Maybe Int) == Nothing)
then do
putStrLn "(integer input required, please try again)"
lp_reqInt
else let output = fromMaybe (-666) (readMaybe input1 :: Maybe Int)
return output
尝试编译此错误会在最后一行给出parse error (possibly incorrect indentation or mismatched brackets)
的可疑简单错误。 (整个文件中没有使用缩进字符)
如何更改代码以具有预期的行为?那有可能吗?
答案 0 :(得分:3)
另一个答案讨论了什么地方出了问题以及最小的解决方法。除了可以使您继续进行代码工作的最低限度的东西之外,我认为显示惯用的修补程序(也就是使用模式匹配而不是if
)可能也很有趣。所以:
lp_reqInt :: IO Int
lp_reqInt = do
input1 <- getLine
case readMaybe input1 of
Nothing -> do
putStrLn "(integer input required, please try again)"
lp_reqInt
Just n -> return n
这不需要使用-666
中的奇怪的回退fromMaybe
,这很好。使用模式匹配而不是(==)
也有一个更微妙的优势:它不需要基础类型具有Eq
实例。对于Int
,只有一个,因此在此代码中没有优势,但在其他情况下,它可能更重要。我还将类型签名提升到了顶层。 see here,以进一步讨论该习语。
答案 1 :(得分:1)
您似乎对do
-符号的工作方式有点误解。
我给你一个“正确的”版本,我们可以解决这个问题:
lp_reqInt = do
input1 <- getLine
let maybeInput = readMaybe input1 :: Maybe Int
if maybeInput == Nothing
then do putStrLn "(integer input required, please try again)"
lp_reqInt
else return $ (\(Just x) -> x) maybeInput
请注意顶部的let
语句。我可以在此处执行let
语句,而不是let
-in
语句,因为它位于do
块的顶层。当您编写let output = fromMaybe (...)
时,它不在do
语句的顶层,而是在if
语句的第二部分,因此它将不起作用。>
由于这个原因,您遇到了解析错误:GHC期望伴随着in
!
答案 2 :(得分:0)
以前的答案很好,但我只是想对那些最终不是在搜索OP所要的而是在搜索相关内容的人提供另一种合理的方法来扩展这个主题。
由于该主题提到了用户输入(IO
)和整数(Maybe Int
),因此我们最终使用了{{1} }。此类类型最好在Monad变形金刚下表达,即IO (Maybe Int)
,它们也很好地充当MaybeT IO Int
类成员。
对于这些情况,Haskell有出色的解决方案,因此我们可以解决类似的问题;
Alternative
这是无情的:)
import Control.Monad (msum)
import Control.Monad.Trans.Maybe
import Control.Monad.Trans (lift)
import Text.Read (readMaybe)
lp_reqInt :: MaybeT IO Int
lp_reqInt = msum . repeat $ (lift . putStrLn) "Enter an integer.." >>
(MaybeT $ readMaybe <$> getLine)