haskeem-0.6.10: fibo.scm
; Fibonacci routines, good & bad: these also show how to use trace
; $Id: fibo.scm,v 1.2 2009-05-26 04:22:10 uwe Exp $
; efficient Fibonacci function: use accumulator to calculate in linear time
(define (fibo n)
(define (fibo-acc i a1 a2)
(if (= i 1)
a1
(fibo-acc (- i 1) (+ a1 a2) a1)))
(trace fibo-acc #t)
(cond ((< n 1) 0)
((= n 1) 1)
(else (fibo-acc n 1 0))))
; inefficient Fibonacci function: straight from definition,
; but exponential time
(define (bad-fibo n)
(cond ((< n 1) 0)
((= n 1) 1)
(else (+ (bad-fibo (- n 1)) (bad-fibo (- n 2))))))
(trace bad-fibo #t)
; identical to bad-fibo, defined just so that we have an independent
; copy to play with
(define (memo-fibo n)
(cond ((< n 1) 0)
((= n 1) 1)
(else (+ (memo-fibo (- n 1)) (memo-fibo (- n 2))))))
(trace memo-fibo #t)
; cache access: a cache is a list of dotted-pairs, with the car of
; each pair being the argument, and the cdr being the function value.
; return (#t . fval) if found, (#f . #f) if not found
(define (get-cache cache in)
(cond ((null? cache) (cons #f #f))
((eqv? (caar cache) in) (cons #t (cdar cache)))
(else (get-cache (cdr cache) in))))
; return a memoized version of the given function
(define (memoize fn)
(if (procedure? fn)
(let ((cache ()))
(lambda (arg)
(let ((cval (get-cache cache arg)))
(if (car cval)
(cdr cval)
(let ((nval (fn arg)))
(set! cache (cons (cons arg nval) cache))
nval)))))
fn))
(write-string "Defined (fibo n), (bad-fibo n), and (memo-fibo n)\n"
"(bad-fibo) and (memo-fibo) act identically until you run\n"
"\n"
"\t(set! memo-fibo (memoize memo-fibo))\n"
"\n"
"then, shazam! (memo-fibo) will act just like (fibo)\n"
"(actually, even better)\n")