0

When there are many data types which have almost same structure, how can I implement without almost-duplicated codes?

Here is uncompilable code sample to explain the goal.

{-# LANGUAGE DuplicateRecordFields #-}

class Category a where
  method :: a -> String

class ForB b where
  ...
class ForC c where
  ...

data A = A {someA :: String, ...}

data B1 = B1 {some :: Int, ...}
data B2 = B2 {some :: Int, ...}
...

data C1 = C1 {some :: Int, ...}
data C2 = C2 {some :: Int, ...}
...

instance Category A where
  method (A x) = x

-- Cannot be compiled, but I want to write like this.
instance Category a where
  method = show . some

instance ForB B1 where
  ....

instance ForC C1 where
  ....

main = do
  let a = A "1"
      b = B1 2
      c = C1 3
  print . method $ a
  print . method $ b
  print . method $ c

I understand that instance does not take type variable a like instance Something a but takes only real data type; Is there no polymorphic instance?
I've tried to solve this by introducing new classes like this, but could not figure it out. I concerned phantom types or type families, but I could not find any solution.

I do not want to implement almost same code for each data types. Please refer better explanation and sample to the goal on the background.

Is there any way to short-hand to implement polymorphic(?) instances without reducing data type or Template Haskell (lens,record,extensive package).

Background

I'm preparing series of sample code for transition from OOP to a functional approach.

Here is the simplified base code of the explanation. And here is little improvement with DuplicateRecordFields.
You can see there are massive instance implements. (Please do not ask me why do not combine LifeInfo, AnimalInfo and Human in a data type. This is one of the series to solve bunch of problems)
However, to implement Human, Elf, Pine and Rose, I write almost same instances for each. And there are some exceptions for LifeInfo, AnimalInfo, and PlantInfo.

Some points

  • Do not combine entry data types(A, B, and C) to a data type by using data constructor like data ABC = A {..} | B {..} | C {..}.
    But when you can introduce a method for distinguishing each of them by type-checking or implement class-method like things, it will be good.
    Please notice that there are classes ForB and ForC.
  • I'm avoiding Template Haskell and libraries using TH to solve this problem.
QuietJoon
  • 490
  • 5
  • 16
  • 1
    Have you tried [`deriving`](http://stackoverflow.com/a/3864801/736957)? See also [GHC.Generics wiki](https://wiki.haskell.org/GHC.Generics). – laughedelic Nov 16 '16 at 02:57
  • I just forget about it. Thanks. I'll try it. – QuietJoon Nov 16 '16 at 03:02
  • A [default signature](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#default-method-signatures) on the functions inside `ForA` and `ForB` would allow you to simply write `instance ForA X` for an appropriately defined `X`. – user2407038 Nov 16 '16 at 12:22

0 Answers0