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?
Functions can also be passed as arguments or returned (as we have seen). Their types are given in the type signature. *Main> :t map map :: (a -> b) -> [a] -> [b] *Main> :t filter filter :: (a -> Bool) -> [a] -> [a] flip_args :: (a -> b -> c) -> b -> a -> c flip_args f x y = f y x.
In most imperative languages functions are called by writing the function name and then writing its parameters in parentheses, usually separated by commas. In Haskell, functions are called by writing the function name, a space and then the parameters, separated by spaces.
Composing functions is a common and useful way to create new functions in Haskell. Haskell composition is based on the idea of function composition in mathematics. In mathematics, if you have two functions f(x) and g(x), you compute their composition as f(g(x)). The expression f(g(x)) first calls g and then calls f.
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".
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.
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