如何将折叠|地图|都提升到Either monad?

时间:2017-08-31 23:44:57

标签: haskell tree monads either lifting

类型的“地图”
mapIsh :: Traversable t => (a -> Either b c) -> t a -> Either b (t c)

将是一个开始。 (Hayoo找不到一个。)或者是“foldIsh :: (b -> a -> Either l b) -> b -> t a -> Either l b

最重要的是(对于我的情况)是这样的:

mapAccumIsh :: (a -> b -> Either l (a, c)) -> a -> t b -> Either l (a, t c)

这可能是您需要阅读的全部内容。如果你想要更多细节,这里有一个具体的例子:

想象一下将阿克苏姆映射过的树状结构。每个分支在评估其子代后,都会通过其子代和累加器的某些功能进行转换。

这里有一些工作代码,可以将每个Tree的值添加到累加器中,还可以为每个Branch的标签添加其子标签的产品:

module Temp where

import Data.List

data Tree = Leaf Float | Branch Float [Tree] deriving (Show)

label :: Tree -> Float
label (Leaf i) = i
label (Branch i _) = i

f :: Float -> Tree -> (Float, Tree)
f i (Leaf j) = (i+j, Leaf j)
f i (Branch j ts) = (i + tf, Branch tf ts2) where
  (i2, ts2) = mapAccumL f i ts
  tf = j + (foldl (*) 1 $ map label ts2)

-- the problem: what if instead of (*) in the line above, we used this?
evenMult :: Float -> Float -> Either String Float
evenMult a b = case even $ round b of True -> Right $ a * b
                                      False -> Left "that's odd" 

go = f 0 $ Branch 2 [Branch 2 [Leaf 2]
                    ,Branch 2 [Leaf 2, Leaf (-2)]]

这是返回的内容:

(-6.0,Branch (-6.0) [Branch 4.0 [Leaf 2.0]
                    ,Branch (-2.0) [Leaf 2.0,Leaf (-2.0)]])

但是,如果不使用foldl中的(*),我们使用了evenMult?

0 个答案:

没有答案