授予可遍历的 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
依赖于 subtree
和 according 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
的能力。这就是为什么 []
的 join
是 concat
。 Applicative
只让你们一起粉碎此前毫无关联的 f
s.
免费 monad 的 Free
构造函数包含一整套 f
的 Free 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)
和 f
的 Traversable
。我的第一直觉是 traverse
和 f
折叠包含的子树:
cataA f (Fix xs) = _ $ traverse (cataA f) xs
球洞现在的目标类型是 m (f a) -> m a
。因为有一个 f :: f a -> m a
敲门声,让我们尝试在 m
下转换包含的 f
s:
cataA f (Fix xs) = _ $ fmap f $ traverse (cataA f) xs
现在我们有一个 m (m a) -> m a
的目标类型,即 join
。所以你毕竟需要 Monad
。
我有这个 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
依赖于 subtree
和 according 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
的能力。这就是为什么 []
的 join
是 concat
。 Applicative
只让你们一起粉碎此前毫无关联的 f
s.
免费 monad 的 Free
构造函数包含一整套 f
的 Free 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)
和 f
的 Traversable
。我的第一直觉是 traverse
和 f
折叠包含的子树:
cataA f (Fix xs) = _ $ traverse (cataA f) xs
球洞现在的目标类型是 m (f a) -> m a
。因为有一个 f :: f a -> m a
敲门声,让我们尝试在 m
下转换包含的 f
s:
cataA f (Fix xs) = _ $ fmap f $ traverse (cataA f) xs
现在我们有一个 m (m a) -> m a
的目标类型,即 join
。所以你毕竟需要 Monad
。