从Data.Data.Data了解gfoldl的类型签名

时间:2015-03-18 10:48:25

标签: haskell types type-signature scrap-your-boilerplate

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

gfoldl
  :: (Data a)
  => (forall d b. Data d => c (d -> b) -> d -> c b) 
  -> (forall g. g -> c g)   
  -> a  
  -> c a

cc (d -> b)的目的是什么?为什么它不仅仅是一个常规的折叠,比如

gfoldl'
  :: (Data a)
  => (forall d. Data d => r -> d -> r)
  -> r
  -> a  
  -> r

1 个答案:

答案 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函数gmapQgmapT(以及其他一些函数)。 gmapQgmapT的类型为:

gmapQ :: Data a => (forall d. Data d => d -> u) -> a -> [u]
gmapT :: Data a => (forall b. Data b => b -> b) -> a -> a

gmapQa折叠为u的统一列表,并且可以 使用gfoldl'来表达,gmapT无法做到这一点。

但是,对于gfoldl,我们可以使用c = Identity来启用我们 gmapTc = Const之类的内容可以获得类似gmapQ的内容。

有关详细信息,您可能还需要查看文件Scrap your boilerplate Reloaded,其中显示gfoldl是普通的( 在该论文中称为Spine的数据类型的高阶折叠。

使用身份和常量仿函数来获得转换和转换 从单个底层表示更新行为有一些 与你如何从" van Laarhoven"获得镜头操作相似镜片