{- HASKELL - LAZY EVALUATION AND INFINITE DATA STRUCTURES CSE 341, Autumn 2008 -} module InfiniteDataStructures where {- Since Haskell uses lazy evaluation, we can have infinite data structures -- we only produce as much of the structure as is needed. We've seen various examples of this, for example [1.. ] [1,3 ..] verylargetree (from TypesNotes.hs) -} my_member :: Eq a => a -> [a] -> Bool my_member x [] = False my_member x (y:z) | x==y = True | otherwise = my_member x z -- this works: my_member 10 [1..] -- this searches forever: my_member 3 [10..] -- MEMBER FUNCTION FOR SORTED LISTS sorted_member :: Ord a => a -> [a] -> Bool sorted_member x [] = False sorted_member x (y:z) | x==y = True | xy = sorted_member x z {- this version of member will always terminate. For example sorted_member 3 [10..] terminates immediately -} -- SQUARE ROOT sqt x = head (filter close_enough (approximations x)) where approximations a = a : approximations ((a + x/a)/2) close_enough root = abs (x-root*root) < 1.0e-6 -- to show the list of successive approximations: trial_roots x = approximations x where approximations a = a : approximations ((a + x/a)/2) -- INFINITE LIST OF PRIME NUMBERS factors n = [k | k <- [1..n], n `mod` k == 0] dullprimes = filter isprime [2..] where isprime p = (factors p == [1,p]) {- Fibonacci numbers (clear but inefficient recursive version) -} rec_fib 1 = 1 rec_fib 2 = 1 rec_fib n = rec_fib (n-1) + rec_fib (n-2) {- map2 is like map but takes a 2-argument function (we'll use it for another version of Fibonacci numbers) -} map2 :: (a -> b -> c) -> [a] -> [b] -> [c] map2 f [] [] = [] map2 f (x:xs) (y:ys) = f x y : map2 f xs ys map2 f [] (y:ys) = error "different length lists to map2" map2 f (x:xs) [] = error "different length lists to map2" {- some would argue that better style would be to replace the last two definitions with map2 f xs ys = error "different length lists to map2" This has one less pattern, but depends on the order in which they are given (the other version is order-independent). -} {- Infinite list of Fibonacci numbers. This uses a common pattern for Haskell infinite list definitions, in which you have a prime-the-pump sort of recursive definition. -} fibs = 1 : 1 : map2 (+) fibs (tail fibs) {- HAMMING NUMBERS The Hamming numbers are defined as the list of all numbers of the form 2^a * 3^b * 5*c for non-negative integers a, b, and c; in other words, numbers whose only prime factors are 2, 3. and 5. -} my_merge (x:a) (y:b) | xy = y : my_merge (x:a) b ham = 1: my_merge ham2 (my_merge ham3 ham5) ham2 = map (*2) ham ham3 = map (*3) ham ham5 = map (*5) ham {- take 100 ham evaluates to: [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384, 400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, 729, 750, 768, 800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200, 1215, 1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536] -} {- Infinite list of prime numbers using the Sieve of Eratosthenes. See http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes -} interestingprimes = sieve [2..] where sieve (p:x) = p : sieve [n | n <- x, n `mod` p > 0] {- Why Infinite Lists? Are infinite lists (and other infinite data structures) simply curiosities or something more important? Simon Thompson in "The Craft of Functional Programming" argues that they are more important, for two reasons: First, an infinite version of a program can be more abstract and simpler to write, since we don't need to know in advance how long to make the list (e.g. the fibonacci number list). Second, we can often modularize the generation of values, and separate out some transformations we perform on them. We can then link process-style programs that involve recursion. (Thompson gives a simulation example.) -}