我可以根据 'recursion schemes' `cata` 编写 `foldr`(或 `foldMap`)吗?
Can I write `foldr` (or `foldMap`) in terms of 'recursion schemes' `cata`?
我最近 read about recursion schemes 其中变质现象被描述为类似于广义 foldr
。
是否可以在所有情况下根据 cata
编写 Foldable
的实例(通过 foldr
或 foldMap
)?
foldMap
作为 Foldable
的基本操作,比 foldr
更适合实施。答案是肯定的。 cata
只处理递归;它不会告诉您 "find" 结构中所有值的位置。 (同理,用foldr
实现foldMap @[]
仍然需要知道[]
的内部细节。)这样做需要a little help:
class Bifoldable f where
bifoldMap :: Monoid m => (a -> m) -> (b -> m) -> f a b -> m
然后您可以定义
foldMapDefault ::
(Recursive (f a), Base (f a) ~ b a, Bifoldable b) =>
Monoid m => (a -> m) -> f a -> m
foldMapDefault f = cata (bifoldMap f id)
这使您可以执行以下操作
data Tree a = Leaf | Branch (Tree a) a (Tree a)
makeBaseFunctor ''Tree
deriveBifoldable ''TreeF
instance Foldable Tree where foldMap = foldMapDefault
(虽然你可能刚刚在 Tree
上说了 deriving Foldable
。)为了最大限度的通用性,你可能想要更像这样的东西(我说 "want"...)
newtype Fixed f a = Fixed { getFixed :: f a }
newtype Bibase f a b = Bibase { getBibase :: Base (f a) b }
instance (forall a. Recursive (f a), Bifoldable (Bibase f)) =>
Foldable (Fixed f) where
foldMap :: forall a m. Monoid m => (a -> m) -> Fixed f a -> m
foldMap f = cata (bifoldMap f id . Bibase @f @a @m) . getFixed
你现在可以说
data Tree a = Leaf | Branch (Tree a) a (Tree a)
makeBaseFunctor ''Tree
deriveBifoldable ''TreeF
deriving via TreeF instance Bifoldable (Bibase Tree)
deriving via (Fixed Tree) instance Foldable Tree
但现在您的 Base
仿函数可以更不规则:
data List a = Nil | Cons a (List a)
type instance Base (List a) = Compose Maybe ((,) a)
instance Recursive (List a) where
project Nil = Compose Nothing
project (Cons x xs) = Compose (Just (x, xs))
instance Bifoldable (Bibase List) where
bifoldMap f g (Bibase (Compose Nothing)) = mempty
bifoldMap f g (Bibase (Compose (Just (x, xs)))) = f x <> g xs
deriving via (Fixed List) instance Foldable List
你often can, but not universally。它所需要的只是一个反例。存在几种,但请考虑(我)想到的最简单的一种。
虽然完全没有必要,you can define Boolean values with an F-algebra:
data BoolF a = TrueF | FalseF deriving (Show, Eq, Read)
instance Functor BoolF where
fmap _ TrueF = TrueF
fmap _ FalseF = FalseF
由此(如链接文章所解释的),您可以推导出变形:
boolF :: a -> a -> Fix BoolF -> a
boolF x y = cata alg
where alg TrueF = x
alg FalseF = y
类型 Fix BoolF
与 Bool
同构,后者不是参数多态的(即它没有类型参数),但存在变形。
另一方面,Foldable
类型 class 是为参数多态容器 t
定义的,例如
foldr :: (a -> b -> b) -> b -> t a -> b
由于 Bool
不是参数多态的,所以它不可能是 Foldable
,但存在变形。 The same is true for Peano numbers。
另一方面,对于参数多态类型,您经常(也许总是?)可以。这是树 defined with its catamorphism:
的 Foldable
实例
instance Foldable TreeFix where
foldMap f = treeF (\x xs -> f x <> fold xs)
这里是one for Maybe
:
instance Foldable MaybeFix where
foldMap = maybeF mempty
instance Foldable ListFix where
foldr = listF
我最近 read about recursion schemes 其中变质现象被描述为类似于广义 foldr
。
是否可以在所有情况下根据 cata
编写 Foldable
的实例(通过 foldr
或 foldMap
)?
foldMap
作为 Foldable
的基本操作,比 foldr
更适合实施。答案是肯定的。 cata
只处理递归;它不会告诉您 "find" 结构中所有值的位置。 (同理,用foldr
实现foldMap @[]
仍然需要知道[]
的内部细节。)这样做需要a little help:
class Bifoldable f where
bifoldMap :: Monoid m => (a -> m) -> (b -> m) -> f a b -> m
然后您可以定义
foldMapDefault ::
(Recursive (f a), Base (f a) ~ b a, Bifoldable b) =>
Monoid m => (a -> m) -> f a -> m
foldMapDefault f = cata (bifoldMap f id)
这使您可以执行以下操作
data Tree a = Leaf | Branch (Tree a) a (Tree a)
makeBaseFunctor ''Tree
deriveBifoldable ''TreeF
instance Foldable Tree where foldMap = foldMapDefault
(虽然你可能刚刚在 Tree
上说了 deriving Foldable
。)为了最大限度的通用性,你可能想要更像这样的东西(我说 "want"...)
newtype Fixed f a = Fixed { getFixed :: f a }
newtype Bibase f a b = Bibase { getBibase :: Base (f a) b }
instance (forall a. Recursive (f a), Bifoldable (Bibase f)) =>
Foldable (Fixed f) where
foldMap :: forall a m. Monoid m => (a -> m) -> Fixed f a -> m
foldMap f = cata (bifoldMap f id . Bibase @f @a @m) . getFixed
你现在可以说
data Tree a = Leaf | Branch (Tree a) a (Tree a)
makeBaseFunctor ''Tree
deriveBifoldable ''TreeF
deriving via TreeF instance Bifoldable (Bibase Tree)
deriving via (Fixed Tree) instance Foldable Tree
但现在您的 Base
仿函数可以更不规则:
data List a = Nil | Cons a (List a)
type instance Base (List a) = Compose Maybe ((,) a)
instance Recursive (List a) where
project Nil = Compose Nothing
project (Cons x xs) = Compose (Just (x, xs))
instance Bifoldable (Bibase List) where
bifoldMap f g (Bibase (Compose Nothing)) = mempty
bifoldMap f g (Bibase (Compose (Just (x, xs)))) = f x <> g xs
deriving via (Fixed List) instance Foldable List
你often can, but not universally。它所需要的只是一个反例。存在几种,但请考虑(我)想到的最简单的一种。
虽然完全没有必要,you can define Boolean values with an F-algebra:
data BoolF a = TrueF | FalseF deriving (Show, Eq, Read)
instance Functor BoolF where
fmap _ TrueF = TrueF
fmap _ FalseF = FalseF
由此(如链接文章所解释的),您可以推导出变形:
boolF :: a -> a -> Fix BoolF -> a
boolF x y = cata alg
where alg TrueF = x
alg FalseF = y
类型 Fix BoolF
与 Bool
同构,后者不是参数多态的(即它没有类型参数),但存在变形。
另一方面,Foldable
类型 class 是为参数多态容器 t
定义的,例如
foldr :: (a -> b -> b) -> b -> t a -> b
由于 Bool
不是参数多态的,所以它不可能是 Foldable
,但存在变形。 The same is true for Peano numbers。
另一方面,对于参数多态类型,您经常(也许总是?)可以。这是树 defined with its catamorphism:
的Foldable
实例
instance Foldable TreeFix where
foldMap f = treeF (\x xs -> f x <> fold xs)
这里是one for Maybe
:
instance Foldable MaybeFix where
foldMap = maybeF mempty
instance Foldable ListFix where
foldr = listF