
Here's another alternative.
newtype Comp f g a = Comp {unComp :: f (g a)}
instance Resolvable e => Resolvable (Maybe `Comp` e) where resolve db = fmap Comp . resolveMaybe db . unComp
One disadvantage of this approach is that it requires you to pepper
your types with explicit compositions of *->* types via Comp.
On Mon, Mar 5, 2012 at 3:14 AM, Herbert Valerio Riedel
Fair enough, but trying to workaround this by defining a type-synonym to get an (*->*)-kinded expression didn't work either, as currying doesn't seem to be supported at the type-level (is there a language-extension for that?):
The Comp newtype provides the type-level currying you were after, which cannot be done with type synonyms. There is no language-extension for that that I'm aware of. If you want to venture down that rabbit hole, maybe take a look at Her. https://personal.cis.strath.ac.uk/~conor/pub/she/ The other disadvantage of this approach is that Comp only works for a fixed number of arguments. Thus *->*->* types, like pairs, requires Comp2.
newtype Comp2 f g h a = Comp2 {unComp2 :: f (g a) (h a)}
instance (Resolvable e0, Resolvable e1) => Resolvable (Comp2 (,) e0 e1) where resolve db = fmap Comp2 . resolvePair db . unComp2
So, if you don't mind adding types like Comp, Comp2, etc throughout the types in your program/library, this let's you keep Resolvable's parameter as (* -> *) and avoids the type families and constraint kinds. I personally prefer the implicitness and generality of Löh's approach, but I also know that some people (perhaps your users) are shy to the newer type extensions. HTH