Data
defines as one of its core functions gfoldl
:
gfoldl
:: (Data a)
=> (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> a
-> c a
What's the purpose of c
and c (d -> b)
in it? Why isn't it just a regular fold, something like
gfoldl'
:: (Data a)
=> (forall d. Data d => r -> d -> r)
-> r
-> a
-> r
The idea is that a value of an algebraic datatype in Haskell has the form
where
C
is a constructor and thex_i
are the arguments. Whatdoes is to turn such a value into
thereby turning an
a
into ac a
. Let's assume the type ofC
isthen let's look at the types of the intermediate expressions:
The parameterization over
c
allows all these intermediate types to be different. If we'd use a simple fold such asgfoldl'
instead, then all these intermediate types would have to be the same.The motivation for
gfoldl
is to be a single generalization that lets you express the SYB functionsgmapQ
andgmapT
(and a few others). The types ofgmapQ
andgmapT
are:While
gmapQ
collapses ana
into a uniform list ofu
s and could be expressed usinggfoldl'
, this wouldn't be possible forgmapT
.However, with
gfoldl
, we can usec = Identity
to enable us to get something likegmapT
, andc = Const
to get something likegmapQ
.For more details, you may also want to look at the paper Scrap your boilerplate Reloaded which shows that
gfoldl
is an ordinary (yet higher-order) fold of a datatype that is calledSpine
in that paper.The use of the identity and constant functors to obtain both transforming and updating behaviour from a single underlying representation has some similarity to how you obtain the lens operations from "van Laarhoven" lenses.