正在阅读haskell wiki书的monadplus章节:https://en.wikibooks.org/wiki/Haskell/MonadPlus
digit :: Int -> String -> Maybe Int
digit i s | i > 9 || i < 0 = Nothing
| otherwise = do
let (c:_) = s
if [c] == show i then Just i else Nothing
“do-block确保任何失败的模式匹配都会导致返回Nothing。”
然而,当我尝试digit 1 ""
时,它会产生无法反驳的运行时错误,而不是“Nothing”。
我可以使用(c:_) <- return s
解决这个问题。如果有更多经验丰富的哈斯克尔能够证实/澄清这一点,那就太棒了。
答案 0 :(得分:2)
wikibooks中的代码不考虑输入字符串为空时的情况。执行行let (c:_) = s
并且s
为空时,将导致模式匹配失败,并抛出异常。您的建议(c:_) <- return s
实际上与使用的建议完全相似,只有一个区别;当monadic绑定中的模式匹配(即<-
)失败时,将调用monad的fail
方法。现在,在Maybe
monad中,fail
defined始终返回Nothing
,因此会导致整个do
块返回Nothing
。我不喜欢使用你的建议的一件事是,我个人不认为使用fail
是最优雅的解决方案,我宁愿在这种情况下使用case
表达式:
digit :: Int -> String -> Maybe Int
digit i s | i > 9 || i < 0 = Nothing
| otherwise =
case s of
c:_ | [c] == show i -> Just i
_ -> Nothing
事实上,正如您所看到的,我们根本不需要使用do
块。
最后,这是上述代码的更紧凑版本:
digit :: Int -> String -> Maybe Int
digit i s | 0 <= i, i <= 9, c:_ <- s, [c] == show i = Just i
| otherwise = Nothing