CPS 343/543 Lecture notes:
Functional programming in Scheme
Coverage: [EOPL2] §§1.11.2 (pp. 327)
Lists
 what is a set? bag? list?
 we need to cultivate the habit of
inductively (i.e., recursively) specifying data structures
 how do you define a list recursively?
 all functional languages use lists, not just LISP
(see [COPL9] pp. 662 and 672)
Hallmarks of functional languages
 `a functional programming language gives a simple model of programming:
one value, the result, is computed
on the basis of others, the inputs' [COFP]
 functional programming means that programs work
by returning values rather than modifying variables (which is
how imperative programs work)
 functions are firstclass
 can be set to a variable
 can be passed to a function
 can be returned from a function
 they also have types and
 are easy to test in isolation (of the rest of the
program; called interactive or incremental testing)
 anonymous functions
 called closures (lead to LISP macros)
 you have anonymous (nameless) variables
in all your favorite programming languages;
so why not have anonymous functions?
 allows us to refer to functions literally
 no distinction between program, procedure, and function
 no statements, only expressions (all of which return a value)
 no or few sideeffects
 of course, there is I/O
 as a result, bugs have only a local effect
 interactive, simple readevalprint loop (debugging)
 no iteration, only recursion
 automatic garbage collection
 no direct (programmer) manipulation of pointers
 lists are the primary builtin data structure
 values, not variables, have types
 manifest typing
 any variable can hold a value of any type
 less planning can actually lead to a better design
 bottomup programming vs. topdown programming
 oil painting analogy
 involves pattern recognition (design patterns)
 based a λcalculus:
a deep mathematical theory of functions attributed to
mathematician and logician Alonzo Church
 not necessarily only for AI (stereotype)
 usually interpreted
 usually have dynamic features (though Smalltalk has several as well,
recall, OOP has roots in the functional paradigm)
Lambda calculus
`a simple minilanguage which is often used to study the
theory of programming languages' [EOPL2] p. 6
<expression> ::= <identifier>
<expression> ::= (lambda (<identifier>) <expression>)
<expression> ::= (<expression> <expression>)
LISP
 LISP is LISt Processing
 LISP is the second oldest programming language (which is the first?)
 developed by John McCarthy and his students at MIT in 1958 (and it
is still around?)
 two mainstream dialects: Scheme (what we are using in class) and COMMON LISP
 difference between Scheme and COMMON LISP (Paul Graham, Viaweb ... robust)
 extremely simple, uniform, and consistent syntax:
atoms and lists and that's it!
 uses prefix notation for expressions
 uses applicativeorder evaluation (as opposed to lazy evaluation)
 theme in LISP: blurred distinctions between program and data (program
and data have same syntax and representation in memory)
 LISP programs are expressed as lists
(the fundamental LISP data structure);
means a LISP program can generate LISP code
and interpret it on the fly at runtime!
 C is a programming language for writing UNIX;
LISP is a language for writing LISP
 nil and () represent false
 to avoid unnecessary frustration, use an editor which matches parentheses
 use vi or emacs in UNIX
 in vi, ":set sm"
 the Racket editor matches parentheses, whew!
Scheme
 racket is the commandline interface to Racket
 semicolon introduces a comment (to the end of the line)
 simple expressions:
1
2
3
(+ 1 2)
(+ 1 2 3)
(lambda (x) (+ x 1))
((lambda (x) (+ x 1)) 2)
(define inc (lambda (x) (+ x 1)))
(inc 2)
 predicates are functions which return a boolean
and typically end with ?
 a function to find nonnegative powers of numbers
;;; notice no side effects below
(define pow
(lambda (x n)
(cond
((zero? n) 1)
(else (* x (pow x ( n 1)))))))
Lists in LISP
Listbox diagrams
'(a . b)
'(a . (b)) = '(a b)
'(a . (b c)) = '(a . (b . (c))) = '(a b c)
'((a) (b) ((c)))
'((a . b) . c)
'(((a) b) c)
'((a b) c)
Other than language,
what else can we define using contextfree grammars (BNF)?
 data structures (inductive or recursive specification)
 algorithms (naturally reflect the data structure)
 most fundamental theme of a course on data structures and algorithms:
data structures and algorithms are natural reflections of each other
 see rule on [EOPL2] p. 12 (top)
Simple functions
 BNF for a list of numbers:
<listofnumbers> ::= ()  (<number> . <listofnumbers>)

(define listofnumbers?
(lambda (lst)
(or (null? lst)
(and (number? (car lst)) (listofnumbers? (cdr lst))))))
 called topdown or recursive descent parsing
(contrast with bottomup or shiftreduce parsing)
 length of a list:
(define length
(lambda (l)
(cond
((null? l) 0)
(else (+ 1 (length (cdr l)))))))

(define nthelt
(lambda (lst n)
(cond
((null? lst)
(eopl:error 'nthelt "List too short by ~s elements.~%" (+ n 1)))
((zero? n) (car lst))
(else (nthelt (cdr lst) ( n 1))))))
 fragile vs. robust programs (we will tend to write fragile programs)
 classic function to concatenate two lists (a Scheme builtin):
(define append
(lambda (x y)
(cond
((null? x) y)
(else (cons (car x) (append (cdr x) y))))))
 what is the runtime complexity of append? O(n). Why?
 append copies first argument, not last
 append copies all arguments except the last
 therefore never use append when cons would suffice
 reversing a list:
(define reverse
(lambda (l)
(cond
((null? l) '())
(else (append (reverse (cdr l)) (cons (car l) '()))))))
 what is the runtime complexity of reverse?
O(n^{2}). Why?
 develop a lineartime
version of reverse
(hint: use cons
instead of append; use difference lists technique
used in function car&cdr; see also The Eleventh
Commandment [TSS])
atoms, lat's, and Slists
 atom? predicate (courtesy [TLS] p. xii)
(define atom?
(lambda (x)
(and (not (pair? x)) (not (null? x)))))
 BNF for a list of atoms:
<listofatoms> ::= ()  (<atom> . <listofatoms>)

(define listofatoms?
(lambda (lst)
(or (null? lst)
(and (atom? (car lst)) (listofatoms? (cdr lst))))))
 use list? predicate to determine a Slist
 contrast with list function
> (list 'a 'b 'c)
(a b c)
More car and cdr
 where do car and cdr
they derive their names from? the IBM 704 computer
(see [COPL9] p. 671)
 a word in the IBM 704 had two fields, named address
and decrement, which each could store a memory address
 car = contents of address register
 cdr = contents of decrement register
 (caddr lst) = car of cdr of cdr or
(car (cdr (cdr lst)))
 cxr where x is string of up to four a's or d's
 cadr = car of the cdr or (car (cdr lst))
 (caddr lst) means (car (cdr (cdr lst)))
Binary tree with numeric leaves
 BNF: <bintree> ::= <number> 
(<symbol> <bintree> <bintree>)
 examples:
1
2
(foo 1 2)
(bar 1 (foo 1 2))
(baz (bar 1 (foo 1 2)) (biz 4 5))
 ever create a binary tree in C++ or Java this painlessly?

(define countnodes
(lambda (s)
(cond
((number? s) 1)
(else (+ (countnodes (cadr s))
(countnodes (caddr s))
1)))))
 traversals:
 preorder:
(define preorder
(lambda (bintree)
(cond
((number? bintree) (cons bintree '()))
(else
(cons (car bintree) (append (preorder (cadr bintree))
(preorder (caddr bintree))))))))

;;; if inorder returns a sorted list,
;;; then its parameter is a binary search tree
(define inorder
(lambda (bintree)
(cond
((number? bintree) (cons bintree '()))
(else
(append (inorder (cadr bintree))
(cons (car bintree) (inorder (caddr bintree))))))))
 postorder: selfstudy
 making programs more readable:
(define root
(lambda (bintree)
(car bintree)))
(define left
(lambda (bintree)
(cadr bintree)))
(define right
(lambda (bintree)
(caddr bintree)))
(define preorder
(lambda (bintree)
(cond
((number? bintree) (cons bintree '()))
(else
(cons (root bintree) (append (preorder (left bintree))
(preorder (right bintree))))))))
 binary search tree
 BNF: ()  (<key> <binsearchtree> <binsearchtree>)
 context?
 more examples of context:
 concept of setness
 concept of order (e.g., a sorted list)
lat's vs. Slists
(define remove_first
(lambda (a lat)
(cond
((null? lat) '())
((eqv? a (car lat)) (cdr lat))
(else (cons (car lat) (remove_first a (cdr lat)))))))
(define remove_all
(lambda (a lat)
(cond
((null? lat) '())
((eqv? a (car lat)) (remove_all (cdr lat)))
(else (cons (car lat) (remove_all a (cdr lat)))))))
(define remove_all*
(lambda (a l)
(cond
((null? l) '())
((atom? (car l))
(cond
((eqv? a (car l)) (remove_all* a (cdr l)))
(else (cons (car l) (remove_all* a (cdr l))))))
(else (cons (remove_all* a (car l)) (remove_all* a (cdr l)))))))
 theme: follow The First Commandment [TLS]
 two problems with remove_all*:
 computing (car l) more than once
for the same value of l (hint: follow
The Fifteenth Commandment [TSS]); note: (cdr l) is
only being computed once for the same value of l
 passing a to every invocation of remove_all*
even though it does not change (hint: follow
The Twelfth Commandment [TSS])
 selfstudy: member? and member*?
let and let*
(let ((a 1) (b 2))
(+ a b))
((lambda (a b) (+ a b)) 1 2)
; will not work
(let ((a 1) (b (+ a 1)))
(+ a b))
(let* ((a 1) (b (+ a 1)))
(+ a b))
(let ((a 1))
(let ((b (+ a 1)))
(+ a b)))
((lambda (a)
((lambda (b) (+ a b)) (+ a 1)))
1)
 let evaluates its bindings in parallel
 let* evaluates its bindings in sequence
 let* is just syntactic sugar
(term courtesy Peter Landin [SICP] p. 11) for let
 let is just syntactic sugar for lambda
 let does not violate the spirit of functional programming
let and letrec
;; courtesy [TSPL] pp. 6263
;; will not work
(let ((sum (lambda (l)
(cond
((null? l) 0)
(else (+ (car l) (sum (cdr l))))))))
(sum '(1 2 3)))
(letrec ((sum (lambda (l)
(cond
((null? l) 0)
(else (+ (car l) (sum (cdr l))))))))
(sum '(1 2 3)))
(let ((sum (lambda (s l)
(cond
((null? l) 0)
(else (+ (car l) (s s (cdr l))))))))
(sum sum '(1 2 3)))
((lambda (sum) (sum sum '(1 2 3)))
(lambda (s l)
(cond
((null? l) 0)
(else (+ (car l) (s s (cdr l)))))))
letrec is just syntactic sugar for let (pass
recursive function to itself)
lambda is foundational
let's fix remove_all*:
saving results of common subexpressions
to avoid recomputation
Now, we can fix the first problem with remove_all* by
following The Fifteenth Commandment [TSS]).
(define remove_all*
(lambda (a l)
(cond
((null? l) '())
(else (let ((head (car l)))
(cond
((atom? head)
(cond
((eqv? a head) (remove_all* a (cdr l)))
(else (cons head (remove_all* a (cdr l))))))
(else (cons (remove_all* a head)
(remove_all* a (cdr l))))))))))
Factoring the parameter a
from remove_all*
Now, we can fix the second problem with remove_all* by
following the The Twelfth Commandment [TSS].
(define remove_all*
(lambda (a l)
(letrec ((remove_all_helper*
(lambda (l)
(cond
((null? l) '())
(else (let ((head (car l)))
(cond
((atom? head)
(cond
((eqv? a head)
(remove_all_helper* (cdr l)))
(else
(cons head
(remove_all_helper* (cdr l))))))
(else
(cons
(remove_all_helper* head)
(remove_all_helper* (cdr l)))))))))))
(remove_all_helper* l))))
Using let and letrec
to define a function local to a function
 nesting functions
 use
(lambda
(letrec ...))
if the nested function needs to know about one of the arguments
to the outer function (The Twelfth Commandment [TSS])
 use
(letrec
(lambda ...))
if the nested function does not need to know about one of the arguments
to the outer function (because it takes it as an argument itself)
to the outer function (The Thirteenth Commandment [TSS])
Different styles, but functionally equivalent
The following two expressions are functionally equivalent.
The first calls the local function in the body of the letrec.
The second returns the local function in the body of the letrec
and then subsequently calls it.
(letrec ((sum (lambda (l)
(cond
((null? l) 0)
(else (+ (car l) (sum (cdr l))))))))
(sum '(1 2 3 4 5)))
((letrec ((sum (lambda (l)
(cond
((null? l) 0)
(else (+ (car l) (sum (cdr l))))))))
sum) '(1 2 3 4 5))
More syntactic sugar: the named let
Any named let expression can be rewritten as a functionally
equivalent letrec expression. See examples below. Some
think the named let uses cleaner syntax than the
equivalent letrec since it is less verbose.
((letrec ((A (lambda (x) (+ x 1))))
A) 1)
; named let
(let A ((x 1))
(+ x 1))
((letrec ((A (lambda (x l)
(cond
((zero? x) l)
(else (A ( x 1) (cons 'a l)))))))
A) 6 '())
(let A ((x 6) (l '()))
(cond
((zero? x) l)
(else (A ( x 1) (cons 'a l)))))
Speed of execution vs. speed of development
 `I just want to get my work done!'
 don't make me include multiple header files,
change, compile, change, recompile, ad infinitum
 C vs. LISP
 speed of development worth the loss of efficiency?
 consider Moore's Law
 compare with improvement in our development methodologies over
the years
Recap
listboxes
sexpressions
atom?
list vs. list?
Never use append or list where cons will
suffice.
binary trees and tree traversals
making code more readable
;; remove first occurrence of a from lat
remove_first a lat
;; remove all occurrences of a from lat
remove_all a lat
;; remove all from l
;; has 2 problems
remove_all* a l
;; selfstudy
member? and member*?
let
let*
 let evaluates its bindings in parallel
 let* evaluates its bindings in sequence
 let* is just syntactic sugar for let
 let is just syntactic sugar for lambda
 let does not violate the spirit of functional programming
Bind head in let
in remove_all* to avoid recomputing common subexpressions
(The Fifteenth Commandment [TSS]).
sum with let incorrect
sum with let correct
(passing recursive function)
letrec
letrec
is just syntactic sugar for let (pass recursive function to itself).
Realize λcalculus is all we need to create powerful programs.
Using letrec to factor the a parameter
from remove_all*
(The Twelfth Commandment [TSS]).
 patternoriented programming (The First Commandment [TLS])
 use let to avoid computing common subexpressions more
than once (The Fifteenth Commandment [TSS])
 use letrec to factors out arguments which
do not change across recursive applications
(The Twelfth Commandment [TSS])
 use letrec nested inside a lambda
to hide and protect functions (The Thirteenth Commandment [TSS])
 use The Eleventh Commandment [TSS] to develop a lineartime
version of reverse
 only simplify once correct (The Sixth Commandment [TLS])
Levels of functional programming
Concurrent programming
Without sideeffects, modifications to shared memory are
impossible, thereby making functional programs natural
candidates for parallelization.
Concurrent functional programming languages include
Concurrent Haskell, pH (a parallel Haskell from MIT), and Erlang.
References
[COFP] 
S. Thompson. Haskell: The Craft of Functional Programming.
AddisonWesley, Harlow, England, Second edition, 1999.

[COPL9] 
R.W. Sebesta. Concepts of Programming Languages.
AddisonWesley, Boston, MA, Ninth edition, 2010. 
[EOPL2] 
D.P. Friedman, M. Wand, and C.T. Haynes.
Essentials of Programming Languages.
MIT Press, Cambridge, MA, Second edition, 2001. 
[TSPL] 
R.K. Dybvig.
The Scheme Programming Language.
MIT Press, Cambridge, MA, Third edition, 2003.

[TSS] 
D.P. Friedman and M. Felleisen.
The Seasoned Schemer.
MIT Press, Cambridge, MA, 1996.

