guillaume8375
guillaume8375

Reputation: 489

Function definition in Haskell

I'm beginning to learn Haskell with "Learn You a Haskell for Great Good!" and I've made a strange mistake, which I can't find the reason for.

Here is the code I typed:

let xs = [if x < 3 then "bang" else "boom" | x <- xs]

And the the text of the error in GHCi:

No instance for (Num [Char])
arising from the literal `3'
Possible fix: add an instance declaration for (Num [Char])
In the second argument of `(<)', namely `(3)'
In the expression: x < (3)
In the expression: if x < (3) then "bang" else "boom"

But when I type:

let boom xs = [if x < 3 then "bang" else "boom" | x <- xs]

which is the example of the book, I don't have any problem.

Could someone explain my mistake?

Upvotes: 4

Views: 447

Answers (3)

גלעד ברקן
גלעד ברקן

Reputation: 23955

let xs = ... 

means xs equals a list of "bang"s and/or "boom"s, but the condition states that those elements should be tested for <3, which is usually done with numbers, not strings.

let boom xs =...

equates the function 'boom' with the right hand side of the equation, where the parameter 'xs' is the list from which the elements to be tested for <3 are drawn.

Upvotes: 0

Daniel Fischer
Daniel Fischer

Reputation: 183873

Try to give the expression a type.

xs = [if x < 3 then "bang" else "boom" | x <- xs]

So xs is a list, we don't know yet what type its elements have, so let's look at that next. The list elements are

if x < 3 then "bang" else "boom"

which is an expression of type String (aka [Char]).

So xs :: [String]. Since the x from the expression describing the list elements is taken from the list xs itself, it is a String too, and is used in the comparison

if x < 3

Now, 3 is an integer literal, thus it is polymorphic and has type

3 :: Num a => a

So from the expression x < 3, we have

  • a Num constraint from the literal,
  • the type String from the fact that x is drawn from a list of Strings.

Thus we need a Num instance for String to have a well-typed expression.

Usually, there is no Num instance for String (what would a useful one look like?), so you get a type error.

If xs is the argument of a function,

boom xs = [if x < 3 then "bang" else "boom" | x <- xs]

there is no reason why the type of x should be String, hence that works.

Upvotes: 7

sepp2k
sepp2k

Reputation: 370082

Your definition of xs is recursive, that is you're using xs inside its own definition. I don't think that's what you intended.

Since you're using "bang" and "boom" inside the list comprehensions, Haskell knows that xs must be a list of strings (because xs is equal to the result of the list comprehension). Further you say that x is an element of xs (x <- xs), so x must be a String (a.k.a. [Char]). However you do x < 3, which implies that x is a number. The error message means "a String is not a number".

Upvotes: 12

Related Questions