How to iterate through a list, element by element
We can use Maybe
to model whether the index was valid.
nth :: Int -> [a] -> Maybe a
nth 0 (x : _) = Just x
nth n (x : xs) = nth (n - 1) xs
nth _ [] = Nothing
We can pattern match on the index to get our base case, and the list to get the first element and tail.
What you're doing there with (_:x)
is called "pattern matching" in case you didn't know. The general pattern for iterating through a list would be (x : xs)
where x
is head element of the list being matched and xs
is the rest of the list. If you use _
you don't remove anything it is still matched to _
which is the convention for saying "I won't use this".
With that you can make a function like this:
myNth :: [a] -> Int -> a
myNth [] _ = error "out of range"
myNth (x : xs) 0 = x
myNth (_ : xs) n = myNth xs (n - 1)
Whenever myNth
is called it will go top to bottom over those definitions trying to match the patterns to the input. So when you call myNth [10,11] 1
it won't match the first clause because [10,11]
doesn't match an empty list, it won't match the second either because 1
is not 0
and so it will match the third case where it will match the [10,11]
on (10 : [11])
, therefore _
is 10
and xs
is [11]
and 1
will be matched as n
. Then it calls itself recursively, as myNth [11] 0
. Now that will match the second case and it will return x
from the match of [11]
on (11 : [])
Like 414owen said you can use the Maybe a
type to avoid using error
.
P.S.: I don't know how beginner you are but I assume you know of the :
operator, it prepends an element to a list... If you go more in depth (afaik) every list is actually stored as a sequence of a:(b:(c:(d:(e:[]))))
which is equivalent to [a,b,c,d,e]
which is equivalent to a:[b,c,d,e]
etc.