20

The pairs function needs to do something like this:

pairs [1, 2, 3, 4] -> [(1, 2), (2, 3), (3, 4)]
Don Stewart
  • 137,316
  • 36
  • 365
  • 468
unj2
  • 52,135
  • 87
  • 247
  • 375

4 Answers4

44
pairs [] = []
pairs xs = zip xs (tail xs)
Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 21
    You should be ok with just the second line since `zip [] undefined` is `[]` – rampion Mar 30 '10 at 16:12
  • @rampion: You really need to know how zip works internally in order to know that is the case and it would mean that zip (tail xs) xs would not work. That does not seem like a good way to write clear and obvious code. – Robert Massaioli Jun 27 '13 at 10:25
  • On another note, is there a library with this function in it somewhere? – Robert Massaioli Jun 27 '13 at 10:25
  • 1
    @RobertMassaioli: Incorrect. You do not need to know how `zip` works internally, it is enough to know that `zip` is strict in its first argument but conditionally strict in its second argument, which in Haskell, is part of its interface semantics. In other languages, yes, this might be an implementation detail, just not Haskell. – Dietrich Epp Jun 27 '13 at 15:35
  • @RobertMassaioli: I don't see this function in any library. http://www.haskell.org/hoogle/?hoogle=%5Ba%5D+-%3E+%5B%28a%2C+a%29%5D – Dietrich Epp Jun 27 '13 at 15:37
21

You could go as far as

import Control.Applicative (<*>)
pairs = zip <*> tail

but

pairs xs = zip xs (tail xs)

is probably clearer.

Edward Kmett
  • 29,632
  • 7
  • 85
  • 107
  • 1
    Great! I'm a newbie, so it took me some 30 minutes to understand why `zip <*> tail` works, but it was totally worth it. If anyone else is curious as well, take a look here: http://stackoverflow.com/questions/11810889/functions-as-applicative-functors-haskell-lyah and, in the process, read Chapter 11 of LYAH. Nice quote: _"Another instance of Applicative is (->) r, so functions. They are rarely used with the applicative style outside of code golf […]"_ – Bolo Oct 13 '13 at 22:29
  • As per pointfree.io , `pairs = ap zip tail` also works, as `ap` is like `<*>` but for monads. – Caridorc Feb 12 '16 at 14:30
6

Just for completeness, a more "low-level" version using explicit recursion:

pairs (x:xs@(y:_)) = (x, y) : pairs xs
pairs _          = []

The construct x:xs@(y:_) means "a list with a head x, and a tail xs that has at least one element y". This is because y doubles as both the second element of the current pair and the first element of the next. Otherwise we'd have to make a special case for lists of length 1.

pairs [_] = []
pairs []  = []
pairs (x:xs) = (x, head xs) : pairs xs
Chuck
  • 234,037
  • 30
  • 302
  • 389
  • 4
    `pairs (x:y:rest) = (x,y) : pairs (y:rest)` would also work, avoiding the need for `@`, although at the cost of an extra constructor. – ephemient Mar 30 '10 at 22:30
2

Call to the Aztec god of consecutive numbers:

import Control.Monad (ap)
import Control.Monad.Instances() -- for Monad ((->) a)

foo = zip`ap`tail $ [1,2,3,4]
barsoap
  • 3,376
  • 3
  • 23
  • 21