I am fresh to Haskell and I am trying to understand the language by writing some code. I am only familiar with very simple instructions on ghci: head, tail, sum, (*), and the like – very simple.
The function I am trying to make is for solving Pythagoras's theorem for vectors of any number of dimensions. This looks something like this: square root (a^2 + b^2 + c^2 ...)
What I can do in ghci in a few lines, which I am trying to make a function is the following:
sq x = x*x
b = map sq [1,2,3]
a = sum b
x = sqrt b
When I do this I try to include a signature of many sorts, Currently my function looks like this:
mod :: [Num a] => a
mod x = sqrt a
where a = sum [b]
where [b] = map sq [x]
I do not understand the issue when I try to run it:
Expected a constraint, but ‘[Num a]’ has kind ‘*’
• In the type signature:
Main.mod :: [Num a] => a
Constraints in Haskell mean one of the following things: Class constraints, e.g. Show a. Implicit parameter constraints, e.g. ? x::Int (with the -XImplicitParams flag) Equality constraints, e.g. a ~ Int (with the -XTypeFamilies or -XGADTs flag)
The Either type is sometimes used to represent a value which is either correct or an error; by convention, the Left constructor is used to hold an error value and the Right constructor is used to hold a correct value (mnemonic: "right" also means "correct").
What's a typeclass in Haskell? A typeclass defines a set of methods that is shared across multiple types. For a type to belong to a typeclass, it needs to implement the methods of that typeclass. These implementations are ad-hoc: methods can have different implementations for different types.
As you are aware, values can be classified by their type. "foo"
has type [Char]
, Just 'c'
has type Maybe Char
, etc.
Similarly, types can be classified by their kind. All concrete types for which you can provide a value have kind *
. You can see this using the :k
command in GHCi:
> :k Int
Int :: *
> :k Maybe Int
Maybe Int :: *
Type constructors also have kinds. They are essentially type-valued functions, so their kinds are similar to regular functions.
> :t id
id :: a -> a
> :k Maybe
Maybe :: * -> *
But what is Num a
? It's not a type, so it doesn't have kind *
. It's not a type constructor, so it doesn't have an arrow kind. It is something new, so a new kind was created to describe it.
> :k Num Int
Num Int :: Constraint
And Num
itself is a Constraint
-valued function: it takes a value of kind *
and produces a Constraint
:
> :k Num
Num :: * -> Constraint
A thing with kind Constraint
is used to specify the typeclass that a particular type must be an instance of. It is the value that can occur before =>
in a type signature. It is also the "argument" to the instance
"function":
instance Num Int where
...
A few things to adjust:
0) mod
isn't a good name for your function, as it is the name of the modulo function from the standard library. I will call it norm
instead.
1) The type signature you meant to write is:
norm :: Num a => [a] -> a
[a]
is the type of a list with elements of type a
. The Num a
before the =>
isn't a type, but a constraint, which specifies that a
must be a number type (or, more accurately, that it has to be an instance of the Num
class). [Num a] =>
leads to the error you have seen because, given the square brackets, the type checker takes it as an attempt to use a list type instead of a constraint.
Beyond the Num a
issue, you have left out the result type from the signature. The corrected signature reflects that your function takes a list of numbers and returns a number.
2) The Num a
constraint is too weak for what you are trying to do. In order to use sqrt
, you need to have not merely a number type, but one that is an instance of Floating
(cf. leftaroundabout's comment to this answer):
GHCi> :t sqrt
sqrt :: Floating a => a -> a
Therefore, your signature should be
norm :: Floating a => [a] -> a
3) [x]
is a list with a single element, x
. If your argument is already a list, as the type signature says, there is no need to enclose it in square brackets. Your function, then, becomes:
norm :: Floating a => [a] -> a
norm x = sqrt a
where a = sum b
where b = map sq x
Or, more neatly, without the second where
-block:
norm :: Floating a => [a] -> a
norm x = sqrt (sum b)
where b = map sq x
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With