用于控制流程的Monad - 序列,选择和迭代

haw*_*eye 7 monads haskell scala clojure control-flow

我可以看到你如何使用Monad是Haskell for IO - 为这个操作围绕计算创建一个容器.有意义的是,你可以使用Monads"将计算一起插入" - 就像你为数据流操作组成函数一样.

我只是在做什么,你可以使用Monads进行控制流程.现在我理解控制流程是关于序列,选择和迭代.现在我对高阶函数(如map,foldl,filter和zipwith/mapcat)感到满意,以便对列表执行操作.

我的问题是 - 我可以使用monad进行序列化,选择和迭代以实现控制流程吗?(很高兴在Haskell,Scala或Clojure中得到答案)

bhe*_*ilr 6

对于在Haskell测序,你具备的功能>>=和sequence:

(>>=) :: Monad m => m a -> (a -> m b) -> m b
sequence :: Monad m => [m a] -> m [a]
Run Code Online (Sandbox Code Playgroud)

该>>=或绑定功能需要一个单子的行动,从中提取的值,并将其送入返回一个新的单子行动的功能.该sequence函数获取相同类型的monadic动作列表并执行所有这些动作,聚合它们的结果并将其包装为单个动作.

对于迭代,你有mapM和forM(forM = flip mapM)

mapM :: Monad m => (a -> m b) -> [a] -> m [b]
Run Code Online (Sandbox Code Playgroud)

的mapM和forM功能是用于将返回到各元件的动作列表中的一个功能,综合这些结果作为一个单一的动作.

为了选择,我假设你的意思是条件,它在Haskell中实现为if-the-else表达式.它们可以直接在monadic表达式中使用,就像在纯表达式中使用它们一样.但是,您也可以使用某些monad执行选择或至少处理错误.最容易理解的是Maybemonad:

data Maybe a = Nothing | Just a

instance Monad Maybe where
    return a = Just a
    (Just a) >>= f = f a
    Nothing  >>= f = Nothing
Run Code Online (Sandbox Code Playgroud)

它有一个非常简单的实现.从本质上讲,如果你尝试将a序列Nothing化为其他任何东西,它将Nothing每次返回.这为您提供了短路故障的概念:

lookup :: Eq a => a -> [(a, b)] -> Maybe b
-- Looks up a value in a key-value association list

myFunc :: Int -> [(String, Int)] -> Maybe Int
myFunc mult assocList = do
    i <- lookup "foo" assocList
    j <- lookup "bar" assocList
    return $ i * mult + j
Run Code Online (Sandbox Code Playgroud)

在这里,如果查找"foo"失败,则myFunc立即返回Nothing.同样,如果查找"bar"失败,则myFunc立即返回Nothing.只有当两个查找成功时才myFunc进行任何计算.这提供了一种"错误处理".有一个类似的单子Either a

data Either a b = Left a | Right b

instance Monad (Either a) where
    return a = Right a
    (Right a) >>= f = f a
    (Left a)  >>= f = Left a
Run Code Online (Sandbox Code Playgroud)

除了"失败"值可以携带一些上下文之外,它的工作方式非常相似,例如字符串错误消息或失败点的计算状态.