
Wolfgang Jeltsch wrote:
Am Donnerstag, 11. März 2010 00:37:18 schrieb wren ng thornton:
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
Wolfgang Jeltsch wrote: 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