[Hs-Generics] Re: gMap in SYB1

Alexey Rodriguez mrchebas at gmail.com
Mon Jul 21 11:54:39 EDT 2008

Hi Oleg!

On Tue, Jul 1, 2008 at 1:46 PM, <oleg at okmij.org> wrote:

> Hello!
>        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

I have tried the following code:

> data Tricky a = Tricky a Char deriving (Data,Typeable,Show)
> mapTricky :: (Data a,Data b) => (a -> b) -> Tricky a -> Tricky b
> mapTricky = gmap
> tricky1 = Tricky 'a' 'b'
> tr_test1 = mapTricky (=='a') tricky1
> tr_test2 = mapTricky (chr . (+1) . ord) tricky1

The expression tr_test1 prints

*GMap> tr_test1
Tricky True 'b'

as one would expect. However, tr_test2 prints:

*GMap> tr_test2
Tricky 'b' 'c'

Here the transforming function is applied to *both* the functor argument and
the Char value.

The argument of gmap is not only applied to the functor argument but also to
'b' in "tricky1". This problem was already pointed out by Claus.

It is important to remark that although gmap passes the test in the
benchmark, it does not behave like a functorial map. Furthermore, this trick
cannot be reused to implement the crush test.

Nevertheless, it is surprising (to me at least) that you can implement
something close to type changing map, using only SYB's cast operation.

I am going to update the "Comparing libraries" paper to refer to your and
Claus' variants of gmap.

> 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.

Yes. The more flexible type turns what would have been type errors into
strange runtime behaviour:

*GMap> gmap (id::Maybe () -> Maybe ()) (Just ()) :: Bool
*** Exception: SYB1_2/GMap.lhs:(20,26)-(21,45): Non-exhaustive patterns in

*GMap> gmap (id::Maybe () -> Maybe ()) (Nothing::Maybe ()) :: Bool


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/generics/attachments/20080721/4e883a98/attachment.htm

More information about the Generics mailing list