Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does has kind 'Constraint' mean in Haskell

Tags:

haskell

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
like image 984
Mike Brown Avatar asked Dec 13 '16 12:12

Mike Brown


People also ask

What is a constraint in Haskell?

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)

What is left and right in Haskell?

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 is a typeclass Haskell?

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.


2 Answers

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
  ...
like image 168
chepner Avatar answered Sep 17 '22 11:09

chepner


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
like image 42
duplode Avatar answered Sep 20 '22 11:09

duplode