I want to define a new abstract data type which is either a general Number or a Division construct. How would I do that in Haskell?
My first approach was:
data MyMath = MyNum Num
| Div MyMath MyMath
The problem is that the compiler complains about "Num" which is not a data type but a type class. So my second thought would be to solve the problem like this:
data MyMath = MyNum Int
| MyNum Float
| Div MyMath MyMath
But this would not work either as MyNum is used twice which is not allowed, additionaly this approach would not really be polymorphic. So what is the solution to this problem?
EDIT2: After (again) reading the answers I tried to use GADT data constructors. This is some artificial example code:
5 data MyMathExpr a where
6 MyNumExpr :: Num a => a -> MyMathExpr a
7 MyAddExpr :: MyMathExpr b -> MyMathExpr c -> MyMathExpr (b, c)
8 deriving instance Show(MyMathExpr a)
9 deriving instance Eq(MyMathExpr a)
10
11 data MyMathVal a where
12 MyMathVal :: Num a => a -> MyMathVal a
13 deriving instance Show(MyMathVal a)
14 deriving instance Eq(MyMathVal a)
15
16 foo :: MyMathExpr a -> MyMathVal a
17 foo (MyNumExpr num) = MyMathVal num
18 foo (MyAddExpr num1 num2) = MyMathVal (l + r)
19 where (MyMathVal l) = foo num1
20 (MyMathVal r) = foo num2
But something is wrong with line number 18:
test.hs:18:40:
Couldn't match type `b' with `(b, c)'
`b' is a rigid type variable bound by
a pattern with constructor
MyAddExpr :: forall b c.
MyMathExpr b -> MyMathExpr c -> MyMathExpr (b, c),
in an equation for `foo'
at test.hs:18:6
In the first argument of `(+)', namely `l'
In the first argument of `MyMathVal', namely `(l + r)'
In the expression: MyMathVal (l + r)
The same goes for `c'. I guess it's a stupid mistake which I just don't see. Do you?
This solves the problem you're addressing in the code, but doesn't cover for the boolean. If you want to use a class constraint in a data declaration, you do it the way that you would with any other function:
data (Num a) => MyMath a = MyMath {x :: a}