<div dir="ltr">Hey Claus! Sorry for the delay, just after the deadline I got into two more deadlines so I was very busy with paper writing these last weeks!<br><br><div class="gmail_quote">On Fri, Jun 27, 2008 at 10:48 PM, Claus Reinke &lt;<a href="mailto:claus.reinke@talk21.com">claus.reinke@talk21.com</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><div class="Ih2E3d"><br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
wanted to see whether the second argument of Tricky would be (incorrectly)<br>
transformed to Bool. But it turned out that fmap&#39; behaved as expected. So I<br>
</blockquote>
<br></div>
That&#39;s the idea - the wrapped function parameter will be delivered<br>
everywhere by the SYB framework, but will only be applied to the marked type. The marker type should play no other role.</blockquote><div><br>Yes, it looks like sort of defining a local type constant which should not be visible after the transformation.<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;"><div class="Ih2E3d"><br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
On the other hand, I think that using unsafeCoerce as a way to define<br>
generic functions is inelegant and probably bad practice due to possible<br>
runtime failures. However, I must admit that I was surprised when I saw your<br>
trick :).<br>
</blockquote>
<br></div>
Haskell is full of odd corners (eg, the IO model is not backed up by a uniqueness type system, so is really unsafe under the abstraction,<br>
and neither the implementation nor the optimizer are verified by the<br>
type system; the Typeable stuff only works by convention for the<br>
instances; ..).<br>
<br>
Ideally, the language/type system will be extended to be able to<br>
express all the capabilities of gfoldl&#39;s code in gfoldl&#39;s type. But<br>
as long as that isn&#39;t the case, unsafeCoerce allows us to extend<br>
the type system, just as unsafePerformIO allows us to extend<br>
the evaluator. But since we are dealing in extensions, it is up to<br>
us to demonstrate that we haven&#39;t broken anything (well, me,<br>
in this case, but after staring at gfoldl&#39;s type and its implication<br>
for several days, I felt like calling for a little outside perspective:-).</blockquote><div><br>As I said before, I don&#39;t consider this an elegant use of unsafeCoerce. The reason is that if you later want to generalize other functions over type constructors (for example, zipWith), you have to again deal with unsafeCoerce. It would already be a slight improvement if this trick can be encapsulated into a reusable combinator.<br>
<br>If you want to make SYB support definitions that abstract over type constructors, you may want to have a look at &quot;Scrap your Boilerplate Revolutions&quot;. Although, I don&#39;t immediately see a way to generalize gfoldl in order to encode the &quot;lifted spine view&quot;.<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>
My assumption was roughly that &#39;everywhere f&#39; would apply<br>
&#39;f&#39; to all occurences typed &#39;a&#39; provided that &#39;f&#39; has &#39;a&#39; generic<br>
special case for type &#39;a&#39;. That assumption is violated by the<br>
Data instances for (a-&gt;b) and (IO a), so as long as those<br>
instances exist, it is easy to come up with counterexamples<br>
for fmap&#39;. That is why I was asking for the rationale for those<br>
instances - if it was just convenience, they should be dropped,<br>
especially since SYB doesn&#39;t permit overloading to polymorpic<br>
types, so those default instances are not easily bypassed.</blockquote><div><br>Yes, I think I would also prefer those instances to reside in a separate module, so that you can choose not to import them.<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>
Once that is sorted, the next issue is whether the private<br>
marker type can escape and be observed by other means.<br>
fmap&#39; is constructed in such a way that neither &#39;f&#39; nor the<br>
calling context see &#39;X&#39;, so as long as the generic scaffolding<br>
provided by &#39;Data&#39; doesn&#39;t mess up, that should be fine.</blockquote><div><br>Probably this is something you have to prove whenever you define a generic function in this style.<br><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>
For things like traverse&#39;, other operators might be applied<br>
to things coerced to &#39;X&#39;, so that needs to be looked into<br>
and perhaps improved.<div class="Ih2E3d"><br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Probably we&#39;ll get back to you around next week. Meanwhile, you may find<br>
useful to look at the paper we wrote on comparing generic programming<br>
libraries[1]. In particular, you can look at caveats that apply to SYB.<br>
</blockquote>
<br></div>
Yep, I guess I&#39;ll have to look through some more of the<br>
generic papers on my reading heap:-) Btw, the overall idea<br>
behind my experiment is whether we can use &#39;Data/Typeable&#39;,<br>
which can be derived in GHC, to avoid the need for<br>
deriving support for other generic instances (such as Functor,<br>
Traversable). Again, a very pragmatic perspective (what<br>
can we do with the basis we have now, rather than: what<br>
better basis would be like to have?), but closely related to<br>
this list&#39;s aim of a unified generic programming framework.</blockquote><div><br>I think it&#39;s good to see how far the limits of SYB and other libraries can be pushed. But I would personally avoid using gmap as you proposed, until there is a cleaner way to do things or the corner cases are well understood.<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>
Btw, expanding SYB&#39;s invariant maps to variant ones raises the whole issue of co- vs contra-variance: if one really wants to fmap over types containing the parameter type in function types, one would need to handle both positive and negative occurrences, presumably by a pair of dual functions (a-&gt;b, b-&gt;a)?</blockquote>
<div><br>That gives rise to another type transforming map, namely bimap. You can look at its Generic Haskell definition at this URL:<br><br><a href="https://svn.cs.uu.nl:12443/repos/Generic-Haskell/trunk/Generic-Haskell/lib/GH/Prelude.ghs">https://svn.cs.uu.nl:12443/repos/Generic-Haskell/trunk/Generic-Haskell/lib/GH/Prelude.ghs</a><br>
<br>Cheers,<br><br>Alexey<br>&nbsp;</div></div></div>