How to define an abstract data type, for example "data MyMath = MyNum Num"?

I want to define a new abstract data type, which is either a general number construction or a section. How can I do this in Haskell?

My first approach:

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 was to solve the problem as follows:

data MyMath = MyNum Int
            | MyNum Float
            | Div MyMath MyMath

But this will not work, since MyNum is used twice, which is unacceptable, but this approach will not be truly polymorphic. So what is the solution to this problem?

EDIT2 . After (again) reading the answers, I tried using the GADT data constructors. This is some kind of artificial code example:

 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)

`c '. , , . ?

+3
4

, , . , , :

data (Num a) => MyMath a = MyMath {x :: a}

+3

:

> let data MyMath = forall n. Num n => MyNum n
> :t MyNum 3
MyNum 3 :: MyMath
> :t MyNum 3.5
MyNum 3.5 :: MyMath
+3

. - GADT:

{-# LANGUAGE GADTs #-}

data MyMath where
    MyNum :: Num a => a -> MyMath
    MyBool :: Bool -> MyMath

GADT:

{-# LANGUAGE GADTs #-}

data MyMath a where
    MyNum :: Num a => a -> MyMath a
    MyBool :: Num a => Bool -> MyMath a
+1

, , .

, Either . , Either a Bool, , a Num. , .

Edit: If you do not want to use Either, you can do data MyMath a = MyNum a | MyBool Bool. Now you can apply ato the instance Numif you want, but you can consider this SO question and this answer to it . In fact, there is no need to enforce an instance for a data type; just do it for functions using its intsead.

0
source

All Articles