<div dir="ltr">Hi Oleg!<br><br><br><div class="gmail_quote">On Tue, Jul 1, 2008 at 1:46 PM, <<a href="mailto:oleg@okmij.org">oleg@okmij.org</a>> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
Hello!<br>
<br>
It has occurred to me a year ago that the type-changing gMap<br>
is easily possible in SYB. The recent discussion has prompted me to<br>
implement that solution. I have committed a patch to<br>
<br>
<a href="http://darcs.haskell.org/generics/comparison/SYB1_2/GMap.lhs" target="_blank">http://darcs.haskell.org/generics/comparison/SYB1_2/GMap.lhs</a><br>
<br>
with the implementation. I hope this is OK: the previous version of<br>
that file was a stub saying that gMap is not supported. The function<br>
gMap has the expected type<br>
gmap :: (Data a, Data b, Data x, Data y) => (a -> b) -> x -> y</blockquote><div><br>I have tried the following code:<br>
<br>
> data Tricky a = Tricky a Char deriving (Data,Typeable,Show)<br>
> mapTricky :: (Data a,Data b) => (a -> b) -> Tricky a -> Tricky b<br>
> mapTricky = gmap<br>
> tricky1 = Tricky 'a' 'b'<br>
> tr_test1 = mapTricky (=='a') tricky1<br>
> tr_test2 = mapTricky (chr . (+1) . ord) tricky1<br>
<br>The expression tr_test1 prints<br>
<br>
*GMap> tr_test1 <br>
Tricky True 'b'<br>
<br>
as one would expect. However, tr_test2 prints:<br>
<br>
*GMap> tr_test2<br>
Tricky 'b' 'c'<br>
<br>Here the transforming function is applied to *both* the functor argument and the Char value.<br><br>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.<br>
<br>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. <br><br>Nevertheless, it is surprising (to me at least) that you can implement something close to type changing map, using only SYB's cast operation.<br>
<br>I am going to update the "Comparing libraries" paper to refer to your and Claus' variants of gmap.<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
<br>
There are no unsafe operations used; there is not a single occurrence<br>
of insafePerformIO and the ilk. Incidentally, Data.Generics could, in<br>
principle at least, be implemented using a safe cast. Of course gmap<br>
is not a total operation: one can't really expect (gmap id True) to<br>
produce a character. It seems that gunfold is not total anyway.</blockquote><div><br>Yes. The more flexible type turns what would have been type errors into strange runtime behaviour:<br> <br>*GMap> gmap (id::Maybe () -> Maybe ()) (Just ()) :: Bool<br>
*** Exception: SYB1_2/GMap.lhs:(20,26)-(21,45): Non-exhaustive patterns in case<br>
<br>
*GMap> gmap (id::Maybe () -> Maybe ()) (Nothing::Maybe ()) :: Bool<br>
False<br>
<br><br>Cheers,<br><br>Alexey<br><br></div></div></div>