这个想法是 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 折叠成us 的统一列表并且可以
使用gfoldl' 表示,这对于gmapT 是不可能的。
但是,使用gfoldl,我们可以使用c = Identity 使我们能够获得
类似gmapT 和c = Const 得到类似gmapQ 的东西。
更多细节,你可能还想看看论文Scrap your boilerplate Reloaded,它表明gfoldl是一个普通的(然而
在该论文中称为Spine 的数据类型的高阶)折叠。
使用恒等函子来获得变换和
从单个底层表示更新行为有一些
类似于从“van Laarhoven”镜头获得镜头操作的方式。