Home > Blockchain >  Haskell - Num vs Double, Int types
Haskell - Num vs Double, Int types

Time:09-26

Haskell noob here.

Im trying to make the following function and this error is extremely cryptic to me:

:{
myfunc::(Double a)=> a -> a -> a
myfunc a b = a   b
:}

and I get:

error:
    • Expected kind ‘* -> Constraint’, but ‘Double’ has kind ‘*’
    • In the type signature: myfunc :: (Double a) => a -> a -> a

The same goes for Int.

However, it I use Num type, I get no error:

:{
myfunc::(Num a)=> a -> a -> a
myfunc a b = a b
:}

The same goes if I use just plain Int or Double without Double a

:{
myfunc::Double -> Double -> Double
myfunc a b = a b
:}

My question: How come is it, that I can use Num a, or just plan Double, Int, but I cannot use Double a, or Int a?

Regards.

CodePudding user response:

First a terminology note: when GHC writes * here in the error messages, read it as Type, the kind of types. It is for historical reasons that older versions of GHC write it with the asterisk symbol.

So, your error message is

Expected kind ‘Type -> Constraint’, but ‘Double’ has kind ‘Type’
    • In the type signature: myfunc :: (Double a) => a -> a -> a

Ok, ‘Double’ has kind ‘Type’ – that should make enough sense, right? Double is a type.

But why does it say it's “expecting” Type -> Constraint? Well, it means you tried to use Double as if it were of this kind. Namely, you wrote Double a. Here, a has to be a type, but you can't apply a type to another type, that would be like applying a character to a character on the value level:

Prelude> 'x' 'y'

<interactive>:1:1: error:
    • Couldn't match expected typeChar -> t’ with actual typeCharThe function ‘'x'’ is applied to one argument,
      but its typeChar’ has none

By contrast, Num is a type class, and as such it has in fact the correct kind:

Prelude> :k Num
Num :: Type -> Constraint

Constraint is the correct kind that's expected on the left of the =>, so that's why you can write

myfunc :: Num a => a -> a -> a

Again, Double is a type, not a type class, so it can't be used in this way. However, what you can use is an equality constraint:

{-# LANGUAGE TypeFamilies #-}

myfunc :: a~Double => a -> a -> a
myfunc = ( )

This is effectively the same as

myfunc :: Double -> Double -> Double

(there are some subtle differences with respect to typechecking).

Vice versa, it is not possible to write

myfunc :: Num -> Num -> Num
myfunc = ( )

error:
    • Expecting one more argument to ‘NumExpected a type, but ‘Num’ has kind ‘Type -> ConstraintIn the type signature: myfunc :: Num -> Num -> Num

To be completely precise, Type is the kind of lifted types. Don't worry about what that means: unless you're doing very low-level stuff, you may never need to work with unlifted types.

  • Related