[Hs-Generics] Re: gMap in SYB1

Claus Reinke claus.reinke at talk21.com
Tue Jul 1 18:16:22 EDT 2008

Hi Oleg!

> It has occurred to me a year ago that the type-changing gMap
> is easily possible in SYB. The recent discussion has prompted me to
> implement that solution. I have committed a patch to
> http://darcs.haskell.org/generics/comparison/SYB1_2/GMap.lhs
> with the implementation. I hope this is OK: the previous version of
> that file was a stub saying that gMap is not supported. The function
> gMap has the expected type
> gmap :: (Data a, Data b, Data x, Data y) => (a -> b) -> x -> y

Thanks, looks nice. I suspected there had to be a gfoldl+gunfoldl-
based approach, but I couldn't quite wrap my head around it. So
simple in hindsight (given the proper auxiliary type constructors), 
and I might have got there in the end, but it was certainly not 
"easily possible" for me - so thank you for freeing me from the 
daily headache of trying yet another approach!-)

A slight issue: this version does not distinguish functor parameter
from equivalent types:

    *GMap> gmap not (True,True)::(,) Bool Bool

Perhaps we can combine our versions to get the best of both?

> There are no unsafe operations used; there is not a single occurrence
> of insafePerformIO and the ilk. Incidentally, Data.Generics could, in
> principle at least, be implemented using a safe cast. Of course gmap
> is not a total operation: one can't really expect (gmap id True) to
> produce a character. It seems that gunfold is not total anyway.

The latter is the reason why this version is safer than mine, 
I think: 'instance Data (a->b)' implements a fake gfoldl, but
turns uses of gunfoldl into runtime errors. Yet another reason
why those instances are dubious, but any attempt to fake gunfoldl
would have to involve error anyway, it seems (something like
'z (const (error "no such function"))' when grabbing an (a->b)
out of thin air). So your version does at least get a proper runtime 
error in the cases where mine runs right out of type safety..

> Regarding the instance of Data for functions: SmashA does
> define (co-variant) traversal `under lambda'. For example, we can
> (gmap fromEnum) on a function and convert (Bool->Bool) to (Bool->Int).
> Please see testt3 in
> http://darcs.haskell.org/generics/comparison/SmashA/Syb4A.hs
> I do not claim to have any use for that transformation, but it was
> easy to implement...

I was just surprised that the comparison seemed to make no
mention of higher-order (as opposed to higher-kinded) types.

More information about the Generics mailing list