我正在尝试了解monad变换器,我正在阅读haskell wiki上的this page。
我困惑的代码如下:
isValid :: String -> Bool
isValid s = length s >= 5
getValidPassword :: MaybeT IO String
getValidPassword = do s <- lift getLine
guard (isValid s)
return s
askPassword :: MaybeT IO ()
askPassword = do lift $ putStrLn "Insert your new password:"
value <- getValidPassword
lift $ putStrLn "Storing in database..."
到目前为止一切顺利。我可以运行它,它的工作原理。但现在,将askPassword
更改为:
askPassword :: MaybeT IO ()
askPassword = do lift $ putStrLn "Insert your new password:"
value <- msum $ repeat getValidPassword
lift $ putStrLn "Storing in database..."
如果不满足有效条件,这将反复等待我提供新的输入。我有点迷失它是怎么做到的。 repeat
会永久重复此操作,而msum
只是foldr mplus mzero
,这意味着它会沿着列表行进,并将这些值“添加”在一起。
为什么这不会在我输入错误后立即返回(返回值为Nothing)。我想我没有看到决定何时停止以及何时继续的逻辑嵌入的位置。谢谢你的帮助。
答案 0 :(得分:5)
嗯,msum
的{{1}}应该在第一次成功尝试时停止,而不是第一次失败。
答案 1 :(得分:4)
这是有效的,因为MaybeT的mplus在其第二个参数中是非严格的:
mplus (return () :: MaybeT m ()) undefined
相当于
return ()
这是the definition of mplus for MaybeT的结果,如下所示:
instance (Monad m) => MonadPlus (MaybeT m) where
mzero = MaybeT (return Nothing)
mplus x y = MaybeT $ do v <- runMaybeT x
case v of
Nothing -> runMaybeT y
Just _ -> return v
如您所见,除非第一个参数y
无法返回结果,否则不会执行mplus的第二个参数x
。
因此,从msum
获得的无限动作列表中的repeat getPassword
只会在第一个成功之前执行。