gfoldl
:: (Data a)
=> (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> a
-> c a
c
和c (d -> b)
的目的是什么?为什么它不仅仅是一个常规的折叠,比如
gfoldl'
:: (Data a)
=> (forall d. Data d => r -> d -> r)
-> r
-> a
-> r
答案 0 :(得分:14)
这个想法是Haskell中的代数数据类型的值具有
形式C x_1 x_2 ... x_n
其中C
是构造函数,x_i
是参数。什么
gfoldl app con
确实是将这样的值变成
con C `app` x_1 `app` x_2 ... `app` x_n
从而将a
变为c a
。我们假设C
的类型是
C :: T_1 -> T_2 -> ... -> T_n -> D
然后让我们看一下中间表达式的类型:
con C :: c (T_1 -> T_2 -> ... -> T_n -> D)
con C `app` x_1 :: c (T_2 -> ... -> T_n -> D)
con C `app` x_1 `app` x_2 :: c (... -> T_n -> D)
con C `app` x_1 `app` x_2 ... `app` x_n :: c D
c
上的参数化允许所有这些中间类型
不同。如果我们使用简单的折叠,例如gfoldl'
,那么所有
这些中间类型必须相同。
gfoldl
的动机是:
单一泛化,可让您表达SYB函数gmapQ
和gmapT
(以及其他一些函数)。 gmapQ
和gmapT
的类型为:
gmapQ :: Data a => (forall d. Data d => d -> u) -> a -> [u]
gmapT :: Data a => (forall b. Data b => b -> b) -> a -> a
gmapQ
将a
折叠为u
的统一列表,并且可以
使用gfoldl'
来表达,gmapT
无法做到这一点。
但是,对于gfoldl
,我们可以使用c = Identity
来启用我们
gmapT
和c = Const
之类的内容可以获得类似gmapQ
的内容。
有关详细信息,您可能还需要查看文件Scrap your boilerplate Reloaded,其中显示gfoldl
是普通的(
在该论文中称为Spine
的数据类型的高阶折叠。
使用身份和常量仿函数来获得转换和转换 从单个底层表示更新行为有一些 与你如何从" van Laarhoven"获得镜头操作相似镜片