首页 文章

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

提问于
浏览
6

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

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

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

1 回答

  • 5

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

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

    >>= 或bind函数采用monadic动作,从中提取值并将其提供给返回新monadic动作的函数 . sequence 函数获取相同类型的monadic动作列表并执行所有这些动作,聚合它们的结果并将其作为单个动作包装 .

    对于迭代,你有 mapMforMforM = flip mapM

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

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

    为了选择,我假设你的意思是条件,它在Haskell中实现为if-the-else表达式 . 它们可以直接在monadic表达式中使用,就像它们可以在纯表达式中使用一样 . 但是,您也可以使用某些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 才会进行任何计算 . 这提供了一种"error handling" . 有一个类似的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
    

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

相关问题