15

Data定义为其核心功能之一gfoldl

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
4

1 回答 1

15

这个想法是 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 功能gmapQgmapT(以及其他一些)。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成一个统一的us 列表并且可以使用 来表示gfoldl',但这对于 . 来说是不可能的gmapT

但是,gfoldl我们可以使用c = Identity来使我们获得类似的东西gmapT,并c = Const获得类似的东西gmapQ

有关更多详细信息,您可能还想查看论文Scrap your Boilerplate Reloaded,它表明这gfoldl是该论文中调用的数据类型的普通(但更高阶)折叠Spine

使用恒等函子从单个底层表示中获得转换和更新行为与从“van Laarhoven”镜头中获得镜头操作的方式有些相似。

于 2015-03-18T12:00:46.453 回答