next up previous contents
Next: The (untyped) lambda calculus Up: Functional programming in Haskell Previous: Theorem   Contents

Outermost reduction and infinite data structures

Outermost reduction permits the definition of infinite data structures. For instance, the list of all integers starting at n is given by the function

   listfrom n = n: (listfrom (n+1))

The output of listfrom m is the infinite list [m, m+1, ... which is denoted [m..] in Haskell.

We can use infinite lists, for instance, to define in a natural way the Sieve of Eratosthenes whose output is the (infinite) list of all prime numbers.

   sieve (x:xs) = x : (sieve [ y <- xs | mod y x != 0])
   primes = sieve [2..]

The function sieve picks up the first number of its input list, constructs a new list from its input by removing all multiples of the first number and then recursively runs sieve on this list.

If we work out the reduction for this we get

primes   sieve [2..]
    2 : (sieve [ y | y <- [3..] , mod y 2 != 0])
    2 : (sieve (3 : [y | y <- [4..], mod y 2 != 0])
    2 : (3 :
    (sieve [z
| z <- (sieve [y | y <- [4..], mod y 2 != 0])
| mod z 3 != 0])
    2 : (3 : (5 :
    (sieve [w | w <- (sieve [z | z <- (sieve [y | y <- [4..],
    mod y 2 != 0]) | mod z 3 != 0]) | mod w 5 != 0])
    ...

Why is this useful? It is often conceptually easier to define a function that returns an infinite list and extract a finite prefix to get a concrete value.

For instance, from primes we can derive functions such as

   nthprime k = primes !! k

that extracts the kth prime number.


next up previous contents
Next: The (untyped) lambda calculus Up: Functional programming in Haskell Previous: Theorem   Contents
Madhavan Mukund 2004-04-29