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

Pet*_*lák 15 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
Run Code Online (Sandbox Code Playgroud)

有什么目的cc (d -> b)它吗?为什么它不仅仅是一个常规的折叠,类似于

gfoldl'
  :: (Data a)
  => (forall d. Data d => r -> d -> r)
  -> r
  -> a  
  -> r
Run Code Online (Sandbox Code Playgroud)

kos*_*kus 14

我们的想法是Haskell中的代数数据类型的值具有这种形式

C x_1 x_2 ... x_n
Run Code Online (Sandbox Code Playgroud)

where C是构造函数,x_i是参数.什么

gfoldl app con
Run Code Online (Sandbox Code Playgroud)

确实是把这样的价值变成了

con C `app` x_1 `app` x_2 ... `app` x_n
Run Code Online (Sandbox Code Playgroud)

从而变成了a一个c a.我们假设类型C

C :: T_1 -> T_2 -> ... -> T_n -> D
Run Code Online (Sandbox Code Playgroud)

然后让我们看一下中间表达式的类型:

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
Run Code Online (Sandbox Code Playgroud)

参数化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
Run Code Online (Sandbox Code Playgroud)

虽然gmapQ折叠aus 的统一列表并且可以使用表达gfoldl',但这是不可能的gmapT.

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

有关更多详细信息,您可能还需要查看文件Scrap您的样板重新加载,这表明这gfoldlSpine该文件中调用的数据类型的普通(但更高阶)折叠.

使用身份和常量仿函数从单个基础表示获得变换和更新行为与从"van Laarhoven"镜头获得镜头操作的方式有一些相似之处.