How to create a common complex type in haskell?

I want to create a complex type to represent complex numbers.

The following works:

Prelude> data Complex = Complex Int Int Prelude> :t Complex Complex :: Int -> Int -> Complex 

How can I change this to accept any type of Num, not just Int.

I tried the following:

 Prelude> data Complex a = Num a => Complex aa 

but got the following:

 * Data constructor `Complex' has existential type variables, a context, or a specialised result type Complex :: forall a. Num a => a -> a -> Complex a (Use ExistentialQuantification or GADTs to allow this) * In the definition of data constructor `Complex' In the data type declaration for `Complex' 

I am not sure what to do with this error. Any help is appreciated.

+7
haskell
source share
3 answers

Haskell's traditional data is just that: data. He should not know anything about the properties of his fields, he simply should be able to store them. Therefore, there is no real need to limit the fields at this point; just do it

 data Complex a = Complex !a !a 

( ! because strict margins are better for performance).

Of course, when you implement an instance of Num , you will need a restriction:

 instance (Num a) => Num (Complex a) where fromInteger = (`Complex`0) . fromInteger Complex ri + Complex ฯ ฮน = Complex (r+ฯ) (i+ฮน) ... 

... in fact, you need a much stronger restriction on RealFloat a implement abs , at least that the standard version does this . (This means that Complex Int is not actually used, not the standard Num hierarchy; you need, for example, Complex Double .)

However, it is also possible to bake a restriction on the data type itself. The ExistentialTypes syntax you tried is very limited, although not suitable for this; instead you want a gadt

 data Complex a where Complex :: Num a => a -> a -> Complex a 

Using this, you could implement, for example. add without mentioning any signature restrictions

 cplxAdd :: Complex a -> Complex a -> Complex a cplxAdd (Complex ri) (Complex ฯ ฮน) = Complex (r+ฯ) (i+ฮน) 

Now you need to execute Num when you try to build the value of Complex . This means that you still need an explicit restriction on the Num instance.

Also, this version is potentially much slower, because the Num dictionary really needs to be stored in the runtime view.

+11
source share

Type constructors cannot be restricted in pure Haskell, only functions can. Therefore, it is assumed that you declare

 data Complex a = Complex aa 

and then restrict functions like

 conjugate :: (Num a) => Complex a -> Complex a conjugate (Complex xy) = Complex x (-y) 

In fact, the type and constraint for conjugate can be obtained by the compiler, so you can simply define the implementation:

 conjugate (Complex xy) = Complex x (-y) 

However, if you really want to restrict the constructor of Complex types, you can enable some extensions that activate it, namely ExistentialQuantification or GADTs , as the compiler suggests. To do this, add this line to the top of the file:

 {-# LANGUAGE ExistentialQuantification #-} 

or

 {-# LANGUAGE GADTs #-} 

They are called pragmas .

+3
source share

While you could, as indicated in the compiler message, use ExistentialQuantification , you can also define a type like this:

 data Complex a = Complex aa deriving (Show, Eq) 

This is a completely unconditional type, so perhaps a different name would be more appropriate ... This type is often called Pair ...

However, when writing functions, you can limit the values โ€‹โ€‹contained in the type:

 myFunction :: Num a => Complex a -> a myFunction (Complex xy) = x + y 
+2
source share

All Articles