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 li
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
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
...