haskell - 我可以用“递归方案”“cata”来写“foldr”(或“foldMap”)吗?
解决方案
foldMap
,作为 的基本操作Foldable
,比 . 更适合实施foldr
。答案是肯定的。cata
只处理递归;它不会告诉您在哪里“找到”结构中的所有值。(同样,实现foldMap @[]
withfoldr
仍然需要了解 . 的内部细节[]
。)这样做需要一点帮助:
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
(尽管您也可能刚刚说过deriving Foldable
。Tree
)为了最大限度地通用,您可能想要更像这样的东西(我说“想要”......)
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
推荐阅读
- javascript - 无法解析 deno 中的查询
- python - 确定日期时间是在中午之前还是之后
- microsoft-graph-api - 补丁计划程序任务详细信息错误 - Base-64 字符串错误的错误请求
- wpf - 如何自定义工具提示窗口以在 wpf 中有箭头
- javascript - 在缩略图刷新时为 scrollIntoView() 禁用自动垂直滚动
- reactjs - 函数返回类型与 TypeScript 不匹配
- c# - 如何让 NLog 将依赖项注入目标?
- tmux - 如何将密钥发送到在本地 tmux 会话中运行的远程 ssh tmux 会话?
- flutter - 颤振:CupertinoAlertDialog 看起来与官方文档中显示的不同
- javascript - 在 React Helmet/ Gatsby 中插入自定义脚本