This is no different from what others have said, but maybe it should be difficult? There are two main “constructors” for lists and, therefore, two main cases that you need to consider when defining functions from lists: form arguments [] and (:) . the last one, (:) can join everything with a list of these kinds of things, thus 1 s [] - 1:[] or [1] . Or he can join 1 with something like this: 1:(1:[]) ie 1:[1] , i.e. [1,1] , as the special syntax allows.
It would be more obvious what would be wrong if you yourself defined the lists by writing:
data List a = Nil | Cons a (List a) deriving (Show, Eq, Ord)
Using [] and x:xs is just spicy sugar for something like that. Similarly, special String sugar allows you to write "abc" rather than ['a','b','c'] , which is better than 'a':'b':'c':[] . (With the above definition, we would have to write Cons 'a' (Cons 'b' (Cons 'c' Nil))) , which is a bit for a short string!), Although it also explains why ByteString and Text should be preferred for string representation for many goals.) With a more detailed list definition like this, we need to add our own map (or rather fmap ), so we can say
instance Functor List where fmap f Nil = Nil fmap f (Cons first rest) = Cons (f first) (fmap f rest)
Note that when defining fmap for this case, I had to consider both constructor types for my type List, Nil and Cons first rest (or Cons x xs , as it is often written).
Or maybe you didn’t get to the general discussion of a class like Functor in LYAH - in this case, just think that you can define your own map as
listMap f Nil = Nil listMap f (Cons first rest) = Cons (f first) (listMap f rest)
In any case, given this canceled list type correspondence, your actual function definition will be:
apply :: (Num b, Ord b) => (a -> a) -> b -> List a -> List a apply fn Nil = Nil apply fn (Cons first Nil) | n <= 1 = fmap f (Cons first Nil) -- or listMap f (Cons first Nil) | otherwise = apply f (n-1) (fmap f (Cons first Nil))
You have considered the following cases:
apply fn Nil apply fn (Cons first Nil)
Cons first Nil matches first : [] or [first] - i.e. [x] when you write it. But this means that you did not cover all cases, your definition of "is not exhaustive." You did not say how to apply f and n to a list if it contains more than one member. What if the list is of the form Cons x (Cons y Nil) or Cons x (Cons y (Cons z Nil)) , and not Nil (your first line) or Cons x Nil (second line)?
The solution is similar to how others have indicated, or using our list type:
apply :: (Num b, Ord b) => (a -> a) -> b -> List a -> List a apply fn Nil = Nil apply fn (Cons first rest) | n <= 1 = fmap f (Cons first rest) | otherwise = apply f (n-1) (fmap f (Cons first rest))
Here the "variable" rest covers all lists, Nil or not. Thus, we obtain:
*Main> apply (+1) 3 Nil Nil *Main> apply (+1) 3 (Cons 3 Nil) Cons 6 Nil
like you, but also:
*Main> apply (+1) 3 (Cons 0 (Cons 1 (Cons 2 Nil))) Cons 3 (Cons 4 (Cons 5 Nil))