授予可遍历的 F 代数,是否有可能对应用代数进行变形?

Granted a traversable F-Algebra, is it possible to have a catamorphism over an applicative algebra?

我有这个 F-Algebra (),我想在它上面加一个有效的代数。通过绝望的尝试,我设法组合了一个有效的单子变形。我想知道它是否可以推广到一个应用程序,如果不能,为什么。

我是这样定义的 Traversable:

instance Traversable Expr where
    traverse f (Branch xs) = fmap Branch $ traverse f xs
    traverse f (Leaf   i ) = pure $ Leaf i

这是单子变形:

type AlgebraM a f b = a b -> f b

cataM :: (Monad f, Traversable a) => AlgebraM a f b -> Fix a -> f b
cataM f x = f =<< (traverse (cataM f) . unFix $ x)

这就是它的工作原理:

λ let printAndReturn x = print x >> pure x
λ cataM (printAndReturn . evalSum) $ branch [branch [leaf 1, leaf 2], leaf 3]
1
2
3
3
6
6

我现在的想法是,我可以这样重写:

cataA :: (Applicative f, Traversable a) => AlgebraM a f b -> Fix a -> f b
cataA f x = do
    subtree <- traverse (cataA f) . unFix $ x
    value <- f subtree
    return value

不幸的是,这里的 value 依赖于 subtreeaccording to a paper on applicative do-notation,在这种情况下我们无法对 Applicative 进行脱糖。似乎没有办法解决这个问题;我们需要一个 monad 从嵌套的深处浮起来。

这是真的吗?我可以安全地得出结论,只有平面结构可以单独使用应用效果折叠吗?

Can I safely conclude that only flat structures can be folded with applicative effects alone?

你再说一遍!毕竟,"flattening nested structures" 正是使 monad 成为 monad 的原因,而不是只能组合相邻结构的 Applicative。比较两个抽象的签名(一个版本):

class Functor f => Applicative f where
    pure :: a -> f a
    (<.>) :: f a -> f b -> f (a, b)

class Applicative m => Monad m where
    join :: m (m a) -> m a

Monad 添加到 Applicative 的是将 嵌套 m 扁平化为一个 m 的能力。这就是为什么 []joinconcatApplicative 只让你们一起粉碎此前毫无关联的 fs.

免费 monad 的 Free 构造函数包含一整套 fFree f 并非巧合,而免费应用程序的 Ap 构造函数仅包含一个 Ap f.

data Free f a = Return a | Free (f (Free f a))
data Ap f a where
    Pure :: a -> Ap f a
    Cons :: f a -> Ap f b -> Ap f (a, b)

希望这能给你一些直觉,让你知道为什么你应该期望用 Applicative.

折叠树是不可能的

让我们打一点打网球看看效果如何。我们要写

cataA :: (Traversable f, Applicative m) => (f a -> m a) -> Fix f -> m a
cataA f (Fix xs) = _

我们有 xs :: f (Fix f)fTraversable。我的第一直觉是 traversef 折叠包含的子树:

cataA f (Fix xs) = _ $ traverse (cataA f) xs

球洞现在的目标类型是 m (f a) -> m a。因为有一个 f :: f a -> m a 敲门声,让我们尝试在 m 下转换包含的 fs:

cataA f (Fix xs) = _ $ fmap f $ traverse (cataA f) xs

现在我们有一个 m (m a) -> m a 的目标类型,即 join。所以你毕竟需要 Monad