Reputation: 489
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
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
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
Num
constraint from the literal,String
from the fact that x
is drawn from a list of String
s.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
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