控制流的Monads——序列、选择和迭代



我可以看到如何使用Monad-is-Haskell进行IO-来围绕此操作的计算创建一个容器。您可以使用Monad"将计算插在一起",这是有道理的,就像您为数据流操作编写函数一样。

我只是在摸索,你可以使用Monads来控制流量。现在我理解了控制流是关于序列、选择和迭代的。现在,我可以使用map、foldl、filter和zipwith/mapcat等高阶函数来对列表执行操作。

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

对于Haskell中的排序,您有函数>>=sequence:

(>>=) :: Monad m => m a -> (a -> m b) -> m b
sequence :: Monad m => [m a] -> m [a]

>>=或bind函数执行一个一元操作,从中提取值,并将其输入到返回新的一元操作的函数中。sequence函数获取相同类型的一元操作列表,并执行所有这些操作,聚合它们的结果并将其包装为单个操作。

对于迭代,您有mapMforMforM = flip mapM

mapM :: Monad m => (a -> m b) -> [a] -> m [b]

mapMforM函数用于应用一个函数,该函数向列表中的每个元素返回一个操作,将结果聚合为单个操作。

对于选择,我假设您指的是条件语句,它们在Haskell中实现,就像其他表达式一样。它们可以直接用于一元表达式,就像它们可以用于纯表达式一样。但是,您也可以使用某些monad来执行选择或至少处理错误。最容易找到的是Maybe monad:

data Maybe a = Nothing | Just a
instance Monad Maybe where
    return a = Just a
    (Just a) >>= f = f a
    Nothing  >>= f = Nothing

它有一个非常简单的实现。从本质上讲,如果您尝试将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

这里,如果对"foo"的查找失败,则myFunc立即返回Nothing。类似地,如果"bar"的查找失败,myFunc立即返回Nothing。只有当两个查找都成功时,myFunc才会进行任何计算。这提供了一种"错误处理"。有一个类似的monad 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

它的工作原理基本相同,只是"failure"值可以携带一些上下文,例如字符串错误消息或失败时的计算状态。

相关内容

  • 没有找到相关文章

最新更新