Pet*_*lák 15 haskell types type-signature scrap-your-boilerplate
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)
有什么目的c和c (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函数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
Run Code Online (Sandbox Code Playgroud)
虽然gmapQ折叠a成us 的统一列表并且可以使用表达gfoldl',但这是不可能的gmapT.
但是,gfoldl我们可以使用它c = Identity来使我们得到类似的东西gmapT,并c = Const获得类似的东西gmapQ.
有关更多详细信息,您可能还需要查看文件Scrap您的样板重新加载,这表明这gfoldl是Spine该文件中调用的数据类型的普通(但更高阶)折叠.
使用身份和常量仿函数从单个基础表示获得变换和更新行为与从"van Laarhoven"镜头获得镜头操作的方式有一些相似之处.