Reputation: 99
I have this code:
pairs :: [a] -> [(a,a)]
pairs [] = []
pairs xs = zip xs (tail xs)
An example of what this code does:
> pairs "hey"
[('h','e'),('e','y')]
> pairs [1..7]
[(1,2),(2,3),(3,4),(4,5),(5,6),(6,7)]
I was wondering how to do this in recursive ways. I tried this,
pairs (x:xs) = (x,head xs): pairs xs
but it failed with the following exception
> pairs [1..7]
[(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,*** Exception: Prelude.head: empty list
Upvotes: 2
Views: 162
Reputation: 28470
The problem with your attempt is that it assumes xs
to have at least one element or, in other words, the whole input (x:xs)
to have at least two elements, so it fails when it reaches the end.
You can solve this by writing a special case for the one-element list before the "normal" case you've already written:
pairs :: [a] -> [(a,a)]
pairs [_] = []
pairs (x:xs) = (x,head xs):pairs xs
if you also need it to work on empty lists, then you need to keep also the pairs [] = []
case.¹
(¹) Honestly, when I wrote the answer, I had already forgotten you were trying to emulate zip xs (tail xs)
², so I haven't included the case for []
input.
(²) By the way, you really don't need pairs [] = []
in your zip
version of the function, because zip xs (tail xs)
works well with the empty list too, thanks to laziness.
Upvotes: 5
Reputation: 477210
You can work with a pattern that selects the first two elements and recurses on the tail:
pairs :: [a] -> [(a, a)]
pairs [] = []
pairs [_] = []
pairs (x:xs@(x2:_)) = (x, x2) : pairs xs
or with less "unpacking":
pairs :: [a] -> [(a, a)]
pairs [] = []
pairs (x:xs) = go xs x
where go [] _ = []
go (x2:xs) x = (x, x2) : go xs x2
Upvotes: 6