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
Cis a constructor and thex_iare the arguments. Whatdoes is to turn such a value into
thereby turning an
ainto ac a. Let's assume the type ofCisthen let's look at the types of the intermediate expressions:
The parameterization over
callows 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
gfoldlis to be a single generalization that lets you express the SYB functionsgmapQandgmapT(and a few others). The types ofgmapQandgmapTare:While
gmapQcollapses anainto a uniform list ofus and could be expressed usinggfoldl', this wouldn't be possible forgmapT.However, with
gfoldl, we can usec = Identityto enable us to get something likegmapT, andc = Constto get something likegmapQ.For more details, you may also want to look at the paper Scrap your boilerplate Reloaded which shows that
gfoldlis an ordinary (yet higher-order) fold of a datatype that is calledSpinein 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.