[Haskell-cafe] generalized newtype deriving allows the definition of otherwise undefinable functions

wren ng thornton wren at freegeek.org
Fri Mar 12 21:59:33 EST 2010


Wolfgang Jeltsch wrote:
> Am Donnerstag, 11. März 2010 00:37:18 schrieb wren ng thornton:
>> Wolfgang Jeltsch wrote:
>>> Hello,
>>>
>>> some time ago, it was pointed out that generalized newtype deriving could
>>> be used to circumvent module borders. Now, I found out that generalized
>>> newtype deriving can even be used to define functions that would be
>>> impossible to define otherwise. To me, this is surprising since I thought
>>> that generalized newtype deriving was only intended to save the
>>> programmer from writing boilerplate code, not to extend expressiveness.
>> Let's dig down and figure out the problem. When you annotate the type
>> "Wrapped a" with "deriving (Iso a)" what are you saying? You're saying
>> that the compiler should derive an instance (Iso a (Wrapped a)). Well,
>> that instance gives you the method instance conv :: forall f. f a -> f
>> (Wrapped a). The funny thing is that the only implementation for
>> ---something like--- that type would be fmap Wrap.
> 
> If the parameter of f is contravariant then we would need a “contraMap”, not 
> an fmap. Example:

Right, but it's the same basic idea, just violating the (nonexistent?) 
ContraFunctor class instead of the Functor class. The underlying problem 
---which is what I was trying to identify--- is that generalized newtype 
deriving is assuming that every tycon of kind *->* is a functor (i.e., 
co-/contravariant endofunctor on all of Hask), and it's that assumption 
which causes breakage.

My conservative solution to disallow deriving methods where the newtype 
occurs beneath an "unknown" tycon would, I think, still work. The only 
difference is that in addition to considering all instances of 
Functor[1] as "well known" (as well as a few special cases: e.g., the 
first argument to (->) or (,)) we could consider all instances of 
ContraFunctor to be "well known" as well. That is, if there's an 
official version of that class.

My solution is conservative in that it doesn't offer any support for 
GADTs or type families, which are the particular concern in the bug 
tracker ticket. The problem for them is the same one, only it's even 
more pertinent since some things given the kind *->* should really have 
a different kind like |*|->* since their argument is an index instead of 
a type--- which means they're _really_ not functors on Hask.


> Let us look at the Set example from John Meacham. Set is a (covariant) 
> functor, not a contravariant functor. However, it isn’t a functor from and to 
> the category of Haskell types and functions

Right, which is why the assumption that kind *->* implies functorality 
is broken. Again, in some sense even the kind is wrong; it's something 
more like Ord->*, but that only underscores the point.


[1] And Monad since Monad doesn't state the Functor requirement.

-- 
Live well,
~wren


More information about the Haskell-Cafe mailing list