<div dir="ltr">Hi Oleg!<br><br><br><div class="gmail_quote">On Tue, Jul 1, 2008 at 1:46 PM,  &lt;<a href="mailto:oleg@okmij.org">oleg@okmij.org</a>&gt; 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>
 &nbsp; &nbsp; &nbsp; &nbsp;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>
 &nbsp; &nbsp; &nbsp; &nbsp;<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>
 &nbsp; &nbsp; &nbsp; &nbsp;gmap :: (Data a, Data b, Data x, Data y) =&gt; (a -&gt; b) -&gt; x -&gt; y</blockquote><div><br>I have tried the following code:<br>
<br>
&gt; data Tricky a = Tricky a Char deriving (Data,Typeable,Show)<br>
&gt; mapTricky :: (Data a,Data b) =&gt; (a -&gt; b) -&gt; Tricky a -&gt; Tricky b<br>
&gt; mapTricky = gmap<br>
&gt; tricky1 = Tricky &#39;a&#39; &#39;b&#39;<br>
&gt; tr_test1 = mapTricky (==&#39;a&#39;) tricky1<br>
&gt; tr_test2 = mapTricky (chr . (+1) . ord) tricky1<br>
<br>The expression tr_test1 prints<br>
<br>
*GMap&gt; tr_test1 <br>
Tricky True &#39;b&#39;<br>
<br>
as one would expect. However, tr_test2 prints:<br>
<br>
*GMap&gt; tr_test2<br>
Tricky &#39;b&#39; &#39;c&#39;<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 &#39;b&#39; in &quot;tricky1&quot;. 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&#39;s cast operation.<br>
<br>I am going to update the &quot;Comparing libraries&quot; paper to refer to your and Claus&#39; variants of gmap.<br>&nbsp;</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&#39;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>&nbsp;<br>*GMap&gt; gmap (id::Maybe () -&gt; Maybe ()) (Just ()) :: Bool<br>

*** Exception: SYB1_2/GMap.lhs:(20,26)-(21,45): Non-exhaustive patterns in case<br>
<br>
*GMap&gt; gmap (id::Maybe () -&gt; Maybe ()) (Nothing::Maybe ()) :: Bool<br>
False<br>
<br><br>Cheers,<br><br>Alexey<br><br></div></div></div>