4

As I'm not familiar with rank-N types, the type signature of gfoldl is a troublesome for me:

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

The only functions I can think of are \xs y -> ($y) <$> xs and pure, respectively.

Other functions such as gunfold and gmapT have similar problems. So what are notable examples of nontrivial uses of them?

Dannyu NDos
  • 2,458
  • 13
  • 32
  • 3
    There should be a SYB (scrap your boilerplate) tutorial in the 'net. Even more than one. I'd start there, since the relatively low-level primitives like `gfoldl` are very general and hardish to understand at first. Also, SYB is probably not the easiest way to learn rank-N types. – chi Aug 07 '19 at 09:05
  • 1
    Also, SYB is a lot harder to grasp than GHC.Generics (though arguably more elegant), so if you want this for automating instance-generation then you may be better off with Generic. – leftaroundabout Aug 07 '19 at 10:48
  • @leftaroundabout I guess `gfoldl` has some functionalities that GHC.Generics can't cover. – Dannyu NDos Aug 07 '19 at 10:54
  • I wouldn't say it's more elegant; it's just different. `Data.Data` has an "untyped" feel and is "deep", while `GHC.Generics` has a very "typed" feel (though less than `generics-sop`) and is "shallow". My general impression is that `Data.Data` is mostly about offering tools to make AST manipulation convenient, while `GHC.Generics` is more about class defaults and the like. – dfeuer Aug 07 '19 at 17:32

2 Answers2

5

For the gmapT case the mkT function is defined for this purpose in the original paper.

mkT :: (Typeable a, Typeable b ) => (b -> b) -> a -> a
mkT f = fromMaybe id (cast f)

For example to increment all int fields in the A, you can write something like

data A = A {f :: Int, s :: Int} deriving (Data, Typeable)

ex = gmapT (mkT inc) (A 2 3) where 
  inc :: Int -> Int
  inc = (+1)

To make it clearer the ex function can be written like this too:

ex2 = gmapT f (A 2 3) where 
  f :: (Data a ) =>  a -> a
  f a = case cast a of 
    Nothing -> a
    (Just (b :: Int)) -> fromJust $ cast (b + 1)
ekim boran
  • 1,809
  • 12
  • 22
0

Data.Data is part of a generic metaprogramming framework called "Scrap your boilerplate".

Li-yao Xia
  • 31,896
  • 2
  • 33
  • 56