Problem: Given a collection of numbers, determine their sum. Let's assume that the numbers are given in the form of a list.
An ex-Pascal or ex-C programmer new to Scheme is likely to draft something like this:
and then find herself stymied by the absence of a(define sum (lambda (numbers) (define total 0) (while (not (null? numbers)) (begin (set! total (+ total (car numbers))) (set! numbers (cdr numbers)))) total))
while
-loop in Scheme. Eventually,
after carefully working out the syntax and semantics of do-expressions, she
arrives at the following code, which is about as close as Scheme comes to
the Pascal algorithm:
This is correct and reasonably efficient, but it still bears discernible traces of the programmer's struggle against the language.(define sum (lambda (numbers) (do ((total 0) (rest numbers (cdr rest))) ((null? rest) total) (set! total (+ total (car rest))))))
A student who is learning Scheme as her first programming language might think first of recursion:
and then realize that one can gain efficiency by making the procedure tail-recursive:(define sum (lambda (numbers) (if (null? numbers) 0 (+ (car numbers) (sum (cdr numbers))))))
The old hand at Scheme, however, will be familiar with the functional-programming trick that produces the most concise and most efficient version:(define sum (lambda (numbers) (let loop ((rest numbers) (total 0)) (if (null? rest) 0 (loop (cdr rest) (+ total (car rest)))))))
(define sum (lambda (numbers) (apply + numbers)))
This document is available on the World Wide Web as
http://www.math.grin.edu/~stone/events/scheme-workshop/summation.html