04 Control ControlBlocks Common Lisp has 3 basic operators for creating blocks of code progn block tagbody If ordinary function calls are the leaves of a Lisp program these operators are used to build the branches ID: 175244
Download Presentation The PPT/PDF document "Functional Programming" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Functional Programming
04 ControlSlide2
Control-Blocks
Common Lisp has 3 basic operators for creating blocks of code
progn
block
tagbody
If ordinary function calls are the leaves of a Lisp program, these operators are used to build the branchesSlide3
Control-Blocks
> (
progn
(format t “a”)
(format t “b”)
(+ 11 12)
)
ab
23
-> only the value of the last expression is returnedSlide4
Control-Blocks
> (block head
(format t “Here we go.”)
(
return-from
head ‘idea)
(format t “We’ll never see this.”))
Here we go.
IDEA
Calling return-from allows your code to make a sudden but graceful exit from anywhere in a body of code
Expressions after the return-from are not evaluatedSlide5
Control-Blocks
> (block nil
(
return
27))
27
> (dolist (x ‘(a b c d e))
(format t “~A “ x)
(if (eql x ‘c)
(return ‘done)))
A B C
DONESlide6
Control-Blocks
The body of a function defined with
defun
is implicitly enclosed in a
block
with the same name as the function
(
defun
foo
(
)
(return-from
foo
27)
)
(
defun
read-integer
(
str
)
(let
((
accum
0))
(
dotimes
(pos
(length
str
))
(let
((
i
(digit-char-p
(char
str
pos))))
(if
i
(
setf
accum
(+
(
*
accum
10)
i
))
(
return-from
read-integer nil))))
accum
))Slide7
Control-Blocks
Within tagbody, you can use
go
> (
tagbody
(setf x 0)
top
(setf x (+ x 1))
(format t “~A “ x)
(if (< x 10) (
go
top)))1 2 3 4 5 6 7 8 9 10This operator is mainly something that other operators are built upon, not something you would use yourself
Ugly code!!Slide8
Control-Blocks
How to decide which block construct to use?
Nearly all the time you’ll use progn
If you want to allow for sudden exits, use block
Most programmers will never use tagbody explicitlySlide9
Control-Context
let
Takes a body of code
Allows us to establish variables for use
within
the body
> (
let
((x 7)
(y 2))
(format t “Number”)
(+ x y))
Number
9Slide10
Control-Context
>
(
(lambda (x) (+ x 1))
3)
4
(
(lambda (x y)
(format t “Number”)
(+ x y))
7
2)Slide11
Control-Context
One let-created variable can’t depend on other variables created by the same let
(let ((x 2)
(y (+ x 1)))
(+ x y))
((lambda (x y) (+ x y)) 2
(+ x 1))
> (
let*
((x 1)
(y (+ x 1)))
(+ x y))
3
equivalentSlide12
Control-Context
A let* is functionally equivalent to a series of nested lets
(let ((x 1))
(let ((y (+ x 1)))
(+ x y)))
In both let and let*, initial values default to nil
> (let (x y)
(list x y))
(NIL NIL)Slide13
Control- Conditionals
(
if
(oddp that)
(progn
(format t “Hmm, that’s odd.”)
(+ that 1)))
(
when
(oddp that)
(format t “Hmm, that’s odd.”)
(+ that 1))
equivalentSlide14
Control- Conditionals
(if <test> <then form> <else form>)
(if <test> <then form>)
(when <test> <then form>)
(if <test> nil <else form>)
(unless <test> <else form>)Slide15
Control- Conditionals
(defun our-member (obj lst)
(if
(atom lst)
nil
(if
(eql (car lst) obj)
lst
(our-member obj (cdr lst))
))
(defun our-member (obj lst)
(cond (
(atom lst) nil) ((eql (car lst) obj)
lst)
(t
(our-member obj (cdr lst))
)))
equivalent
A Common Lisp implementation will probably implement cond by translating it to the “if” formatSlide16
Control- Conditionals
cond
(
cond
(
<test 1>
<consequent 1-1> …)
(
<test 2>
<consequent 2-1> …)
…
(
<test m>
<consequent m-1> …));
cond
The conditions are evaluated in order until one of them returns true
When one condition returns true, the expressions associated with it are evaluated in order, and the value of the last is returns as the value of the
cond
> (
cond
(99))
; if there are no expressions after the successful conditio
n
99
; , the value of the condition itself is returned. Slide17
Control- Conditionals
case
(case <key form>
(
<key 1>
<consequent 1-1> …)
(
<key 2>
<consequent 2-1> …)
...
(
<key m>
<consequent m-1> …)
) ;caseSlide18
Control- Conditionals
(
defun
month-length (
mon
)
(
case
mon
(
(
jan
mar may jul aug oct
dec
)
31)
(
(
apr
jun
sept
nov
)
30)
(
feb
(if (leap-year) 29 28))
(
otherwise
“unknown month”)))
Keys
Are treated as constants
Will not be evaluated
> (case 99 (99))
The successful clause contains only keys
NILSlide19
Control- Iteration
do
(do
((<parameter 1> <initial value 1> <update form 1>)
(<parameter 2> <initial value 2> <update form 2>)
…
(<parameter n> <initial value n> <update form n>))
(<termination test> <intermediate forms, if any> <result form>)
<body>
)
;do
> (let ((x ‘a))
(do ((x 1 (+ x 1))
(y x
x
))
((> x 5))
(format t “(~A ~A) “ x y)))
(1 A) (2 1)
(
3 2) (4 3) (5 4
)
;on each iteration, x gets its previous
NIL
;value plus 1; y also gets the previous
;valueSlide20
Control- Iteration
do*
Has the same relation to
do
as
let*
does to
let
> (do* ((x 1 (+ x 1))
(y x x))
((> x 5))
(format t “(~A ~A) “ x y))
(1 1) (2 2) (3 3) (4 4) (5 5)
NIL Slide21
Control- Iteration
dolist
> (dolist (x ‘(a b c d)
‘done
)
(format t “~A “ x))
A B C D
DONE
dotimes
> (dotimes (x 5
x
)
; for x = 0 to 5-1, return x
(format t “~A “ x))0 1 2 3 4 5Slide22
Control- Multiple values
In Common Lisp, an expression can return zero or more values
E.g.,
get-decoded-time
returns the current time in nine values
value
Returns multiple values
> (values ‘a nil (+ 2 4))
A
NIL
6Slide23
Control- Multiple values
> ((lambda ( )
(values 1 2)
))
1;
2
If something is expecting only one value, all but the first will be discarded
> (let ((x (values 1 2)))
x)
1Slide24
Control- Multiple values
> (values)
returns no value
> (let ((x (values)))
x)
NIL
Use
multiple-value-bind
to receive multiple values
> (
multiple-value-bind
(x y z) (values 1 2 3)
(list x y z))
(1 2 3)
> (
multiple-value-bind
(x y z) (values 1 2)
(list x y z))
(1 2 NIL)Slide25
Control- Multiple values
> (
multiple-value-bind
(s m h) (get-decoded-time)
(format nil “~A:~A:~A” h m s))
“4:32:13”
We can pass on multiple values as the arguments to a second function using
multiple-value-call
> (
multiple-value-call
#’+ (values 1 2 3))
6
multiple-value-lis
t is like using multiple-value-call with #’list as the first argument
> (
multiple-value-list
(values ‘a ‘b ‘c))
(A B C)Slide26
Control-Aborts
catch
and
throw
(defun super ( )
(catch
‘abort
(sub)
(format t “We’ll never see this.”)))
(defun sub ( )
(throw
‘abort
99)
> (super)99Slide27
Control- Example: Date arithmetic
(defconstant month
#(0 31 59 90 120 151 181 212 243 273 304 334 365))
(defconstant yzero 2000)
(defun leap? (y)
(and (zerop (mod y 4))
(or (zerop (mod y 400))
(not (zerop (mod y 100))))))Slide28
Control- Example: Date arithmetic
(defun date->num (d m y)
(+ (- d 1)
(month-num
m y)
(year-num
y)))
(defun
month-num
(m y)
(+ (svref month (- m 1))
(if (and (> m 2) (leap? y)) 1 0)))
(defun
year-num (y)
(let ((d 0))
(if (>= y yzero)
(dotimes (i (- y yzero) d)
(incf d (
year-days
(+ yzero i))))
(dotimes (i (- yzero y) (- d))
(incf d (
year-days
(+ y i)))))))
(defun
year-days
(y) (if (leap? y) 366 365))Slide29
Control- Example: Date arithmetic
(
defun
num->date (n)
(multiple-value-bind (y left) (
num-year
n)
(multiple-value-bind (m d) (
num-month
left y)
(values d m y))))
(
defun
num-year
(n)
(if (< n 0)
(do* ((y (- yzero 1) (- y 1))
(d (- (year-days y)) (- d (year-days y))))
((<= d n) (values y (- n d))))
(do* ((y yzero (+ y 1))
(
prev
0 d)
(d (year-days y) (+ d (year-days y))))
((> d n) (values y (- n
prev
))))))Slide30
Control- Example: Date arithmetic
(
defun
num-month
(n y)
(if (leap? y)
(
cond
((= n 59) (values 2 29))
((> n 59) (
nmon
(- n 1)))
(t (
nmon
n)))
(
nmon
n)))
(
defun
nmon
(n)
(let ((m (position n month :test #’<)))
(values m (+ 1 (- n (
svref
month (- m 1)))))))
(defun date+ (d m y n)
(num->date (+ (date->num d m y) n)))Slide31
Control- Example: Date arithmetic
> (mapcar #’leap? ‘(1904 1900 1600))
(T NIL T)
> (multiple-value-list (date+ 17 12 1997 60))
(15 2 1998)Slide32
Control
Homework (Due April 7)
Rewrite month-mon to use case instead of svref
Define a single recursive function that returns, as two values, the maximum and minimum elements of a vector