1

I've currently got code following this pattern:

f1' x1 x2 .. xm1 = ...
f2' x1 x2 .. xm2 = ...
.
.
,
fn' x1 x2 .. xmn = ...

instance C D1 where
  f1 = f1'
  f2 = f2'
  .
  .
  .
  fn = fn'

instance C D2 where
  f1 = f1'
  f2 = f2'
  .
  .
  .
  fn = fn'

.
.
.

instance C DN where
  f1 = f1'
  f2 = f2'
  .
  .
  .
  fn = fn'

Basically, I've got a class that I want to implement for a number of datatypes, but all these implementations are the same. But there's a lot of repeated code with the instance implementations, for m functions and n instances, I have to write roughly O(m*n) lines of code, I'd prefer it to be more like O(m+n).

Is there a good way to remove the repetition here? I imagine Template Haskell would do the trick, but I don't want to reinvent the wheel if something to handle this already exists.

Clinton
  • 22,361
  • 15
  • 67
  • 163
  • 1
    If they are all the same, can't you just provide default implementations? – Zeta Mar 23 '17 at 06:13
  • I can't do that sadly, I don't control the class (`C` is actually `Enum` in my case). – Clinton Mar 23 '17 at 06:36
  • 2
    Instead of the abstract example, could you add two of your types as well as your functions? – Zeta Mar 23 '17 at 08:36
  • I don't know if there's something simpler than Template Haskell for this. – chi Mar 23 '17 at 10:28
  • Sometimes in cases like this I put all the definitions of each instance on single line, eases the visual pain and shows the repetition more clearly. – luqui Mar 23 '17 at 16:36

2 Answers2

0

You can provide a default implementation for your class. Take the Functor example:

class  Functor f  where
    fmap        :: (a -> b) -> f a -> f b

     -- | Replace all locations in the input with the same value.
     -- The default definition is @'fmap' . 'const'@, but this may be
     -- overridden with a more efficient version.
    (<$)        :: a -> f b -> f a
    (<$)        =  fmap . const

You can also opt for the deriving option which you can found more information in this question: How does deriving work in Haskell? There is some information on how to control deriving.

Community
  • 1
  • 1
mathk
  • 7,973
  • 6
  • 45
  • 74
0

Maybe you could first create another empty type class:

class SomeD

Then make the types D1 ... DN instances of SomeD using a single line for each type:

instance SomeD D1
-- ...
instance SomeD DN

Then make any instance of the SomeD typeclass an instance of C like so:

instance (SomeD t) => C t where
    f1 = f1'
    -- ...
    fn = fn'

(I'm not sure if this works or if it needs some language extensions but unfortunately I can't test it right now.)

Mekeor Melire
  • 502
  • 5
  • 15
  • This does not work and there's not really an extension which allows it to. The only case where this works is if there are no other implementations of `C`. Yes you can get it to compile but when you try to use it everything gets messy. – luqui Mar 23 '17 at 16:33