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
, andC
) to a data type by using data constructor likedata 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 classesForB
andForC
. - I'm avoiding Template Haskell and libraries using TH to solve this problem.