- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有人可以给出一个 super 简单(几行)的单子(monad)转换器示例,这是不平凡的(即不使用 Identity monad - 我理解)。
例如,有人将如何创建一个执行 IO 并可以处理故障的 monad(也许)?
能证明这一点的最简单的例子是什么?
我浏览了一些 monad 转换器教程,它们似乎都使用 State Monad 或 Parsers 或一些复杂的东西(对于新手来说)。我希望看到比这更简单的东西。我认为 IO+Maybe 会很简单,但我自己真的不知道该怎么做。
我如何使用 IO+Maybe monad 堆栈?
什么会在上面?底部会是什么?为什么?
在哪种用例中需要使用 IO+Maybe monad 或 Maybe+IO monad?创建这样一个复合单子(monad)是否有意义?如果是,何时以及为什么?
最佳答案
这是可用的here作为 .lhs 文件。MaybeT
Transformer 将允许我们像抛出异常一样打破单子(monad)计算。
我将首先快速回顾一些预备知识。跳至 为 IO 添加 Maybe 权限 对于一个工作的例子。
首先是一些进口:
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
In a monad stack IO is always on the bottom.
ST
.
MaybeT m
is a new monad type which adds the power of the Maybe monad to the monadm
- e.g.MaybeT IO
.
MaybeT IO
作为可能+IO monad 堆栈。
Just like
IO Int
is a monad expression returning anInt
,MaybeT IO Int
is aMaybeT IO
expression returning anInt
.
Every expression in a
do
block must be from the same monad.
greet :: IO () -- type:
greet = do putStr "What is your name? " -- IO ()
n <- getLine -- IO String
putStrLn $ "Hello, " ++ n -- IO ()
putStr
不在
MaybeT IO
中单子(monad):
mgreet :: MaybeT IO ()
mgreet = do putStr "What is your name? " -- IO monad - need MaybeT IO here
...
To transform an
IO
expression into aMaybeT IO
expression useliftIO
.
liftIO
是多态的,但在我们的例子中它具有以下类型:
liftIO :: IO a -> MaybeT IO a
mgreet :: MaybeT IO () -- types:
mgreet = do liftIO $ putStr "What is your name? " -- MaybeT IO ()
n <- liftIO getLine -- MaybeT IO String
liftIO $ putStrLn $ "Hello, " ++ n -- MaybeT IO ()
mgreet
中的所有语句来自
MaybeT IO
单子(monad)。
Every monad transformer has a "run" function.
MaybeT IO
,运行函数为:
runMaybeT :: MaybeT IO a -> IO (Maybe a)
ghci> :t runMaybeT mgreet
mgreet :: IO (Maybe ())
ghci> runMaybeT mgreet
What is your name? user5402
Hello, user5402
Just ()
runMaybeT (forever mgreet)
mgreet
除了我们在 IO 中可以做的事情之外,它没有做更多的事情。
askfor :: String -> IO String
askfor prompt = do
putStr $ "What is your " ++ prompt ++ "? "
getLine
survey :: IO (String,String)
survey = do n <- askfor "name"
c <- askfor "favorite color"
return (n,c)
askfor1 :: String -> IO (Maybe String)
askfor1 prompt = do
putStr $ "What is your " ++ prompt ++ " (type END to quit)? "
r <- getLine
if r == "END"
then return Nothing
else return (Just r)
survey1 :: IO (Maybe (String, String))
survey1 = do
ma <- askfor1 "name"
case ma of
Nothing -> return Nothing
Just n -> do mc <- askfor1 "favorite color"
case mc of
Nothing -> return Nothing
Just c -> return (Just (n,c))
survey1
有熟悉的楼梯问题
askfor2 :: String -> MaybeT IO String
askfor2 prompt = do
liftIO $ putStr $ "What is your " ++ prompt ++ " (type END to quit)? "
r <- liftIO getLine
if r == "END"
then MaybeT (return Nothing) -- has type: MaybeT IO String
else MaybeT (return (Just r)) -- has type: MaybeT IO String
askfor2
中的所有声明具有相同的单子(monad)类型。
MaybeT :: IO (Maybe a) -> MaybeT IO a
Nothing :: Maybe String
return Nothing :: IO (Maybe String)
MaybeT (return Nothing) :: MaybeT IO String
Just "foo" :: Maybe String
return (Just "foo") :: IO (Maybe String)
MaybeT (return (Just "foo")) :: MaybeT IO String
return
来自 IO-monad。
survey2 :: IO (Maybe (String,String))
survey2 =
runMaybeT $ do a <- askfor2 "name"
b <- askfor2 "favorite color"
return (a,b)
survey2
并通过键入 END 作为对任一问题的回答来提前结束问题。
MaybeT (return (Just r)) -- return is from the IO monad
return r -- return is from the MaybeT IO monad
MaybeT (return Nothing)
是:
mzero
liftIO
语句总是可以组合成一个
liftIO
,例如:
do liftIO $ statement1
liftIO $ statement2
liftIO $ do statement1
statement2
askfor2
函数可以写成:
askfor2 prompt = do
r <- liftIO $ do
putStr $ "What is your " ++ prompt ++ " (type END to quit)?"
getLine
if r == "END"
then mzero -- break out of the monad
else return r -- continue, returning r
mzero
成为打破单子(monad)的一种方式 - 就像抛出异常一样。
loop1 = do putStr "Password:"
p <- getLine
if p == "SECRET"
then return ()
else loop1
def loop():
while True:
p = raw_prompt("Password: ")
if p == "SECRET":
break
loop2 :: IO (Maybe ())
loop2 = runMaybeT $
forever $
do liftIO $ putStr "Password: "
p <- liftIO $ getLine
if p == "SECRET"
then mzero -- break out of the loop
else return ()
return ()
继续执行,因为我们在
forever
循环,控制传递回do block 的顶部。请注意,
loop2
的唯一值可以返回是
Nothing
这对应于跳出循环。
loop2
更容易编写。而不是递归的
loop1
.
关于haskell - "dummies", IO+Maybe 的最简单的非平凡 monad 转换器示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32579133/
我是一名优秀的程序员,十分优秀!