这个想法是 Haskell 中代数数据类型的值具有以下形式
C x_1 x_2 ... x_n
whereC
是构造函数,x_i
是参数。什么
gfoldl app con
所做的就是把这样一个值变成
con C `app` x_1 `app` x_2 ... `app` x_n
从而将 aa
变成 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
将 an 折叠a
成一个统一的u
s 列表并且可以使用 来表示gfoldl'
,但这对于 . 来说是不可能的gmapT
。
但是,gfoldl
我们可以使用c = Identity
来使我们获得类似的东西gmapT
,并c = Const
获得类似的东西gmapQ
。
有关更多详细信息,您可能还想查看论文Scrap your Boilerplate Reloaded,它表明这gfoldl
是该论文中调用的数据类型的普通(但更高阶)折叠Spine
。
使用恒等函子从单个底层表示中获得转换和更新行为与从“van Laarhoven”镜头中获得镜头操作的方式有些相似。