1

Is there a way to have the compiler derive the functionality that I would write manually as:

instance Class c => Class (Trans c) where
    foo1 = lift foo1
    foo2 = lift foo2
    ...
    foo999 = lift foo999
    bar1 = \a b c -> lift $ bar1 a b c
    ...
    baz1 = lift . baz1
    ...

i.e. when a type of class Class is being wrapped in Trans, is it possible to get a free instance of Class for Trans automatically without having to do the heavy lifting :)?

jakubdaniel
  • 2,233
  • 1
  • 13
  • 20
  • 2
    I'm not sure I understood what you actually want. That instance will work on all `c`, so you only have to write it once. I don't think it can be made any shorter, in the general case. – chi Mar 21 '16 at 10:32
  • But the instance is boring (it just does lifting for all the functions), maybe one could write this concisely (by not having to enumerate all the `fooX = lift fooX` etc.) – jakubdaniel Mar 21 '16 at 11:46
  • 1
    I see, but any alternative (e.g. Template Haskell) looks worse, unless you really have a large number of class methods. – chi Mar 21 '16 at 11:51
  • 1
    And if you have enough class methods to justify Template Haskell for that, you should consider redesigning your class. – dfeuer Mar 21 '16 at 13:38
  • I'm not sure I follow this; are you looking for `GeneralizedNewtypeDeriving`? https://downloads.haskell.org/~ghc/7.8.4/docs/html/users_guide/deriving.html#newtype-deriving – Michael Mar 21 '16 at 19:22

1 Answers1

1

If lift is itself a type class function, you can write a general definition for all instances of the type class. Something like:

instance (Class c, Trans t) => Class (t c)

Be careful that this doesn't overlap with any other instances, and is what you want for all these types.

As a more complete example, this code works, even though it's results are sometimes surprising.

{-# LANGUAGE FlexibleInstances #-}

module Inst where

import Control.Applicative (liftA2)

instance (Applicative f, Num n) => Num (f n) where
  (+) = liftA2 (+)
  (*) = liftA2 (*)
  abs = fmap abs
  signum = fmap signum
  fromInteger = pure . fromInteger
  negate = fmap negate
bergey
  • 3,041
  • 11
  • 17
  • Writing an instance for the application of a type variable to something is *almost never* the right approach, so I don't particularly like it as a suggestion. – dfeuer Mar 22 '16 at 17:35
  • I actually need a specific instance for the bottom-most transformer and I would use lifting only in the rest of the transformers. – jakubdaniel Mar 23 '16 at 10:36