SlideShare a Scribd company logo
1
Allegro CL Certification
Program
Lisp Programming Series Level 2
2
Goals for Level 2
• Build on Level 1
– Assumes you can write functions, use the
debugger, understand lists and list processing
• Detailed Exposure To
– Functions
– Macros
– Object­oriented programming
3
Format of the Course
• One 2­hour presentation each week
– Lecture
– Question and answer
– Sample code
• Lecture notes available online
(http://www.franz.com/lab/)
• Homework
• One­on­one help via email
4
Session 1 (today)
• Advanced features of Lisp functions
• Structures, Hash Tables, Bits and Bytes
• Macros
• Closures
5
Session 2
Common Lisp Object System (CLOS)
• Top Ten things to do in CLOS
• Classes, instances, and inheritance
• Methods
• Class precedence list
• Programming style
6
Session 3
• Performance considerations with CLOS
• The garbage collector
• Error conditions
• Using the IDE to make Windows™ windows
7
Homework
• Lisp is best learnt by hands­on experience
• Many exercises for each session
• Will dedicate class time to reviewing
exercises
• Email instructor for one­on­one assistance
doing the homework or any other questions
relevant to the class
– training@franz.com
8
Getting Allegro Common Lisp
• This class is based on version 6.2.
• Trial version should be sufficient for this
module
– Download free from http://www.franz.com/
– Works for 60 days
• I will be using ACL on Windows
• You can use ACL on UNIX, but the
development environment is different,
and I won't be using it.
9
Allegro CL Certification
Program
Lisp Programming Series Level 2
Session 2.1.1
Functions
10
Ways to define functions
• defun
• lambda
• flet
• labels
11
Defun
(defun double (x)
"Doubles the number"
(declare (fixnum x))
(+ x x))
(defun fn­name arglist
optional­doc­string
optional­declarations
code)
12
Argument List
• Contains names for variables
• that get their values from arguments provided in
calls to the function
• persist throughout the body of the function
• are not typed
• May contain optional and keyword
arguments
13
Keyword Arguments
(defun print­array­size (array
&key
(stream *standard­output*)
UseGraphics)
(let ((size (length array)))
(if UseGraphics
(drawsize size stream) ; then
(print size stream)) ; else
size)))
• Call the function like this:
– (print­array­size *my­array*)
• Or like this:
– (print­array­size *my­array* :stream my­open­file)
14
Keyword Arguments
• Call the function with any number of the keyword
arguments, in any order
• Arguments specified as name/value pairs
– :stream my­open­file
• Costs a couple microseconds
– Because Lisp must parse the argument list
• Use when some arguments are only rarely needed
– Source code in callers is greatly simplified
• Or when different calls will need different groups of
arguments
15
Keyword Detail
&key (stream *standard­output*) UseGraphics
• &key specifies the arguments that follow are
keyword arguments
• Each argument can either be a two­element list, a
three­element list, or a single symbol
– Three­element list is used for supplied­p arguments,
described later on
• Default value of an argument, when not passed by
the caller, is the second element of the
two­element list, or NIL if not otherwise
specified
16
Optional Arguments
(defun print­array­size (array
&optional
(stream *standard­output*)
UseGraphics)
(let ((size (length array)))
(if UseGraphics
(drawsize size stream) ; then
(print size stream)) ; else
size)))
• Call the function like this:
– (print­array­size *my­array*)
• Or like this:
– (print­array­size *my­array* my­open­file)
17
Optional Arguments
• Call the function with any number of the optional
arguments
• Lisp determines which one is which by position
– To specify the second optional argument, you must
always specify the first as well
• Costs a couple microseconds
– Because Lisp must parse the argument list
• Use when some arguments are only rarely needed,
and when there aren't very many of them
– Source code in callers is greatly simplified
18
Other possibilities
(defun incr (n &optional inc)
;; if the value of inc was not specified,
;; or if it was specified but not a number,
;; then set it to 1.
(if (not (numberp inc)) (setq inc 1))
(+ n inc))
(defun incr (n &optional (inc 1 increment­p))
;; increment­p TRUE when argument was specified
;; by caller
(if (and increment­p (not (numberp inc)))
(print "non­numeric increment"))
(+ n inc))
19
Optional and Keyword Arguments
• Ways to specify the argument
• <name> ­­ defaults to nil
• (<name> <default value>)
• (<name> <default value> <supplied­p>)
• Use optionals for small numbers of non­
required arguments that are easy to
remember
• Use keywords with either large numbers of
non­required arguments or ones that
are hard to remember
20
&rest example
(defun add (&rest numbers)
(let ((sum 0))
(dolist (n numbers)
(setq sum (+ sum n)))
sum))
• Call it this way:
• (add 1 2 4)
• Or this way:
• (add 9 1 8 4 8 6)
21
&rest Arguments
• Caller may pass any number of arguments,
there is no limit
• Lisp combines all the arguments into a single
list
• Needed only rarely
• Generally used when all the arguments have
the same type and will participate equally in
the operation
22
Pointers to Functions
• The usual way of calling a function:
– (+ 3 4)
• Alternative way:
– (funcall #'+ 3 4)
• #'+ is a pointer to the function "+"
• Function pointers can be passed as
arguments, returned from functions, or stored
as data
23
Pointers to Functions
• #’add
– Is a reference to the function named ADD
(defun combiner (n)
(if (typep n 'list) #'list #'+))
;; Example of returning a function pointer
;; from a function.
(setq *combiner* (combiner 3))
24
Calling a Function by its Pointer
• #'+
– #<FUNCTION +>
• (funcall #'+ 3 4 5 6)
– 18
• (apply #'+ (list 3 4 5 6))
– 18
25
Using Function References
• Functions can be used just like any other type
object
(defun combiner (x)
(typecase x (number #'+) (list #'append) (t #'list)))
COMBINER
USER(49): (defun combine (&rest args)
(apply (combiner (first args)) args))
COMBINE
USER(50): (combine 2 3)
5
USER(51): (combine '(a b) '(c d))
(A B C D)
USER(54): (combine 'a 'b 'c)
(A B C)
26
Function References
• Commonly used in sorting routines
– (sort '(5 1 4 6) #'<)
– #'< small numbers first
– #'> big numbers first
– #'string< A before Z
– #'string> Z before A
• Often used when mapping over a collection
(vector, list, hash table, etc.)
– (mapcar #'print '(5 1 4 6))
27
Lambdas
• Nameless fns
• (setq function #'(lambda (x y) (* x y)))
• (setq function #'(lambda (x y) (+ x y)))
• (funcall function 3 4)
28
Lambda ­ Example
• Example
(defun increment­all (&rest numbers)
(mapcar #'(lambda (x) (+ x 1))
numbers))
• (increment­all 5 6 7 8)
• (6 7 8 9)
29
Where do you use lambdas
• When a function will have only one caller
and it is relatively trivial
• Saves using up you namespace
• Seeing the code in place may improve
readability in some situations
• Commonly used with mapping functions
30
Other Functions of Functions
• Many tools available to investigate your
environment
31
fboundp
• Determines if a symbol is associated with a
function definition or function binding
(fboundp 'double)
#<Interpreted Function DOUBLE>
32
fdefinition
• (fdefinition '+) retrieves the function
object associated with the argument. Same
as symbol­function for symbols, but also
works on names that are lists (such as
(setf foo)).
• Function­lambda­expression retrieves the
definition, if it is available (but the
argument must be a function object, not a
function name)
33
fmakunbound
• (fmakunbound 'add)
• makes the function named ADD become
undefined
• analogous to makunbound for variables
34
Symbol­function
• Returns a symbol’s fn
• Note: you can also setf this
> (setf (symbol­function 'double) #'(lambda (x) (+ x x)))
#<Interpreted Function DOUBLE>
> (double 5)
10
35
Global .vs. Local Functions
• Defun’s are global
• Lambda’s can only be used in place unless
the are assigned or stored on something
• flets and labels can be used to create fns that
are only available in a local context
36
Local Functions ­ labels
• Enables you to define a function and use it
within the scope of the labels
• Think of it like a let* for functions
(defun test­3rd ()
(labels ((3rd (lst)
(first (rest (rest lst)))))
(print (3rd '(1 2 3 4)))
(print (3rd '(a b c d)))))
37
SETF Functions
• setf is useful when you have a pair of
operations for getting and setting a value
• In other languages, you would name the pair
Get­xxx and Set­xxx
• With setf, you have only one name
• (first list) ; gets first element of list
• (setf (first list) 17) ; sets first element to 17
38
SETF Function Definition
;;; Get the first element
(defun 1st (list)
(car list))
;;; Set the first element
(defun (setf 1st) (new list)
(rplaca list new)
new)
39
Using SETF
(setq a '(one two three))
(1st a)
­> ONE
(setf (1st a) 1)
­> 1
(1st a)
­> 1
a
­> (1 two three)
40
Many Operations in Lisp itself
are setf­enabled
• first, second, third, last, nth, elt
• aref, fill­pointer
• Elements or fields of a structure
• Elements or slots of a CLOS instance
• symbol­value, symbol­function
• gethash
41
The Idea of Mapping Functions
• You pass a “pointer to a function” as one of
the arguments
• The “pointer to a function” is applied to each
element of a collection
• The results of the individual calls may be
collected up into a list
42
mapcar
• (mapcar fn list &rest more­lists)
• Example:
> (mapcar #'print '(a b c))
A
B
C
(A B C)
> (mapcar #'cons '(a b c) '(1 2 3))
((A . 1) (B . 2) (C . 3))
43
maphash
• (maphash function hash­table)
– Hash tables covered in more detail later
(maphash #'(lambda (key value)
(format t "~&k=~A,v=~A" key value)
ht)
44
The Idea of Multiple Values
• Sometimes you want a function to return
more than one value
• Option 1: Make an object that contains the
values
– (defun foo () (list 1 2))
• Option 2: Use Lisp multiple values
– (defun foo () (values 1 2))
– 1 is said to be the “first value”
– 2 is said to be the “second value”
45
multiple­value­setq
• Use it like setq to capture multiple values
(let ((x 0)(y 0))
(print x) (print y) ; values before
(multiple­value­setq (x y) (foo))
(print x) (print y) ; values after
)
46
Multiple­Value­Bind
• Use it like let or let* to capture multiple
values in new local variables
(multiple­value­bind (left right) (foo)
(print left)
(print right))
47
Allegro CL Certification
Program
Lisp Programming Series Level 2
Session 2.1.2
Structures and Hash Tables
48
User­defined structures
• Can either use CLOS instances or defstructs
– both store data in a user­defined form
– instances can have behavior in addition
– defstructs are more efficient, but less powerful
• Designed to look similar in code
– slot references look like function calls
– can switch between them during development
49
Structures
• Define with defstruct
• create one with (make­<name> …)
• access slot with <name>­<slotname>
> (defstruct route­segment
node­number
start
end)
ROUTE­SEGMENT
> (setf rs (make­route­segment :node­number 5 :start 2 :end 7))
#S(ROUTE­SEGMENT NODE­NUMBER 5 START 2 END 7)
> (route­segment­start rs)
2
50
defstruct with default values
• Example
> (defstruct point
(x 0)
(y 0))
POINT
> (setf pt (make­point))
#S(POINT X 0 Y 0)
51
Structures
• Standard Lisp Structures are really just
vectors.
• Accessing an element of a structure is as fast
as accessing an element of an array.
• The reader functions generated by defstruct
get compiled into an vector access of a
specific position (fast!)
• If you redefine the positions, you have to
recompile your code
52
defstruct with type
• Example
> (defstruct (point (:type list))
(x 0)
(y 0))
POINT
> (setf pt (make­point :x 10 :y 20))
(10 20)
53
defstruct with type and name
• Example
> (defstruct (point (:type list) (:named t))
(x 0)
(y 0))
POINT
> (setf pt (make­point :x 10 :y 20))
(POINT 10 20)
54
Hash tables
• Pair­oriented: Associate keys with values,
just like alists and plists
• Could use lists for small ones, but search
time grows proportional to size of list
• hash table computes hash function to use as
index
– speed largely independent of size
• have to build your own in many other
languages
55
Hash table examples
> (setf ht (make­hash­table))
#<HASH­TABLE #xDD7410>
> (gethash 'color ht)
NIL
NIL
> (setf (gethash 'color ht) 'brown)
BROWN
> (gethash 'color ht)
BROWN
T
56
gethash’s Multiple values
• gethash returns two values
– value associated with key or NIL
– Whether or not the value was found
• Second value helps you distinguish between
– NIL as the value of the key
– NIL as the value you get when the key has no
value
57
Hash Table Fns
• Examples
> (hash­table­p ht)
(#<STRUCTURE­CLASS HASH­TABLE #x891668>)
> (gethash 'color ht)
BROWN
T
> (remhash 'color ht)
T
> (gethash 'color ht)
NIL
NIL
58
clrhash
• Examples:
(setf ht (make­hash­table))
#<HASH­TABLE #xE02D8C>
> (setf (gethash 'color ht) 'brown)
BROWN
> (gethash 'color ht)
BROWN
T
> (clrhash ht)
#<HASH­TABLE #xDD8280>
59
Hash table iteration example
(let ((test (make­hash­table)))
(setf (gethash 'a test) "This is the a value")
(setf (gethash 'b test) "This is the b value")
(maphash #’(lambda (sym str)
(format t "~&~A = ~S" sym str))
test))
B = "This is the b value"
A = "This is the a value"
NIL
60
maphash
• Iterate over the contents of the hash table,
pair by pair
• (maphash #'(lambda (key value) ..code..) hash)
61
Allegro CL Certification
Program
Lisp Programming Series Level 2
Session 2.1.3
Bits and Bytes
62
Bits and Bytes
• Normally represented as lisp integers
• Often used for efficiency
– Speed: some operations may compile into a
single machine instruction
– Size: a bit vector is much smaller than a general
vector
• Often used in combination with foreign
function calls
– Arguments to C++ and WIN32 libraries are often
several "flags" passed as a single integer
63
Bits of Integers
• The #b prefix means a binary notation
USER(1): #b10
2 ; decimal integer 2
USER(2): *print­base*
10 ; numbers normally print in decimal
USER(3): (let ((*print­base* 2)) (print #b10) nil)
10 ; decimal integer 2 printed in binary
NIL
USER(4):
64
Bit Combination
• Inclusive OR of bits
USER(1): (logior #b100 #b110)
#b110
• AND of bits
USER(1): (logand #b100 #b110)
#b100
• Less commonly: logxor, logeqv, lognand,
lognor, logandc1, logandc2, logorc1, logorc2
65
Bit Testing
• (defvar *mask* #b1010)
• (logtest flags *mask*)
– True if the second or fourth bit in FLAGS is “on”
• (logbitp 1 flags )
– True if the second bit in FLAGS is “on”
• (logcount flags)
– Counts the number of bits that are “on”
66
Byte Manipulation with ldb
• USER(1): (setq flags #b111000111)
• USER(2): (ldb (byte 4 0) flags)
• #b0111 ; lowest (rightmost) four bits
• USER(3): (ldb (byte 4 4) flags)
• #b1100 ; next four bits
• USER(4): (ldb (byte 8 0) flags)
• #b11000111 ; lowest eight bits
67
Byte Manipulation
USER(5): (setf (ldb (byte 4 4) flags) #b0011)
USER(6): flags
#b100110111
• This line modifies the second four bits of the
bit field.
68
Shift Operation
• ash ­­ arithmetic shift (left)
– (ash 1 10) ­­> 1024
– (ash 255 ­6) ­­> 3
• Note that there is no assumption of integer
size. You eventually get a bignum if you
keep shifting left.
69
How Many Bits?
• (integer­length #b1000) => 4
• Use it to print a binary number:
(defun binary­to­string (bits)
(let* ((L (integer­length bits))
(string (make­string L
:initial­element #0)))
(dotimes (I L)
;; Note that bit zero is on the right
;; of the string (character L­1).
(when (logbitp (­ L I 1) bits)
(setf (char string I) #1)))
string))
70
Vectors of Bits
(setq vector (make­array 1024 :element­type ‘bit
:initial­element 0))
;; Access and modify as any vector or array
(setf (aref vector 0) 1)
;; But elements must be either zero or one
(setf (aref vector 0) 2) ; ERROR
71
Allegro CL Certification
Program
Lisp Programming Series Level 2
Session 2.1.4
Macros
72
What are Macros?
• Macros take lisp code as input and return lisp
code as output. For example,
When evaluating: (incf x)
Evaluate this instead: (setf x (+ 1 x))
(defmacro incf (place)
(list 'setf place (list '+ 1 place)))
73
Macroexpansion
• When the evaluator sees (incf a)
– It notices that INCF names a macro
– It “runs” or macroexpands the macro, which
transforms the line of code into:
• (setf a (+ 1 a))
– It evaluates that expression instead
– So when you type (incf a) to the lisp listener, it
is as if you had typed (setf a (+ 1 a))
74
Macro Evaluation is Different
• for functions
– gets the function name
– evaluates all the args
– applies the function to the eval’ed args
• for macros
– passes arguments without evaluating them
– the macro function returns another expression
– evaluator evaluates that expression instead of the
original
75
Recursive Macros
• Macros can macroexpand into other macros
• For example
– WHEN macroexpands into COND
– COND macroexpands into IF
• The evaluator (and the compiler) recursively
macroexpand an expression until there are no
more macros left
76
Macroexpand function
• macroexpand is function which lisp uses to
call macro function and get result
– it keeps recursively macro­expanding till no
macros are left
• macroexpand­1 just does one step of
macroexpansion
• (macroexpand­1 '(incf x))
– (setq x (+ x 1))
77
macro functions
• stored in same function cell of symbol
• stored in a different format so that the system
can tell it is a macro function
• macro­function <symbol> will return nil if
the symbol has a normal function definition
or none, but will return the expansion
function if the symbol names a macro
78
Macro Examples
• Macros are just functions that transform expressions
• Use macroexpand­1 to see definition
> (defmacro nil! (x)
(list 'setf x nil))
NIL!
> (setq x 5)
5
> (nil! x)
NIL
> x
NIL
> (macroexpand­1 '(nil! x))
(SETF X NIL)
79
Backquote
• Used extensively in macros
• Used by itself is equivalent to quote
• Protects args from evaluation
• comma (,) will unprotect
> (setq a 1 b 2)
2
> `(a is ,a b is ,b)
(A IS 1 B IS 2)
80
Backquote example
(defmacro incf (place)
`(setf ,place (+ 1 ,place)))
• Compared to earlier definition of INCF, this
version is shorter, more concise, and easier to
understand (but equivalent)
(defmacro incf (place)
(list 'setf place (list '+ 1 place)))
81
,@
• Like comma but splices in list
> (setq lst '(1 2 3 4))
(1 2 3 4)
> `(here are the numbers ,@lst)
(HERE ARE THE NUMBERS 1 2 3 4)
82
&body
• &body is like &rest, but typically reserved for macros
• Example: WITH (shorthand for LET, use it to create
one local variable)
(defmacro with ((var &optional val) &body body)
`(let ((,var ,val))
,@body))
(with (a)
(print a)) ;; this example transforms into:
(let ((a nil))
(print a))
83
with­open­file example
More complex example. There is a built­in lisp macro of the
same name that does almost exactly this.
(defmacro with­open­file ((var &rest args) &body body)
`(let ((,var (open ,@args))) ; open file
(unwind­protect
(progn ,@body) ; execute body
(when (streamp ,var) (close ,var)))) ; close
• unwind­protect is talked about later on, but it
ensures the file is closed even if an error
occurs
84
Macro Examples
• Ordered­bounds
(defmacro order­bounds (left bottom right top)
`(progn (if (> ,left ,right) (rotatef ,left ,right))
(if (> ,bottom ,top) (rotatef ,bottom ,top))))
(setq left 10)
(setq right 0)
(setq top 50)
(setq bottom 4)
(order­bounds left bottom right top)
;; Now LEFT is 0, RIGHT is 10,
;; TOP is 4, BOTTOM is 50
85
Macro Examples
• Add onto the end of the list
(defmacro push­last (item list)
`(setf ,list (nconc ,list (list ,item))))
86
Macro Examples
• Atomic Operations
(defmacro atomic­pop (list)
`(without­interrupts
(pop ,list)))
(defmacro atomic­push (item list)
`(without­interrupts
(push ,item ,list)))
87
Iteration Macro
(defmacro while (test &body body)
`(do ()
((not ,test))
,@body))
;; Prints even numbers
(setq I 0)
(while (< I 10)
(print I)
(incf I 2))
88
Macro Argument Lists
• Use of &key, &optional, &rest is common in macros
(defmacro with­resource­string ((resource­string
&key (size 80))
&body body)
`(let ((,resource­string
(allocate­resource­string :size ,size)))
,@body
(free­resource­string ,resource­string)))
89
Macros with Logic
• A macro need not be just a backquoted list
• A macro is an arbitrarily complex function for transforming
one expression into another
(defmacro incf (place)
(if (symbolp place)
`(setq ,place (+ 1 ,place))
`(setf ,place (+ 1 ,place))))
90
Macro writing problems
• A macro is not a function
– Certain uses are not allowed
• multiple evaluation problem
– Inadvertently evaluate args multiple times
• variable capture problem
– Inadvertently shadow a variable name
91
Macros are not Functions
• (apply #’when (> x 3) x)
– This is an error because APPLY only works on
functions
92
Don’t evaluate more than once
• A macro similar to OR
(defmacro or1 (a b)
`(if ,a ,a ,b))
• What happens for: (or1 (print 1) (print 2))
(if (print 1) (print 1) (print 2))
• To avoid multiple evaluation:
(defmacro or2 (a b)
`(let ((temp ,a))
(if temp temp ,b)))
93
Variable Capture
• How would you implement Lisp’s OR
macro?
(defmacro or2 (a b)
`(let ((temp ,a))
(if temp temp ,b)))
(let ((x nil)
(temp 7))
(or2 x temp))
;; Returns NIL (there are two TEMPs)
94
Generate symbols that can’t be
captured
• Gensym
(defmacro or3 (a b)
(let ((symbol (gensym)))
`(let ((,symbol ,a))
(if ,symbol ,symbol ,b))))
95
Turning Functions into Macros
• Do it to eliminate a function call
• Do it when the function is not recursive
(defun second (x) (cadr x))
(defmacro second (x) `(cadr ,x))
(defun sum (&rest numbers) (apply #’+ numbers))
(defmacro sum (&rest numbers) `(+ ,@numbers))
96
When to Use Macros
• Macros help avoid code duplication
(defmacro with­resource­string ((resource­string
&key (size 80))
&body body)
`(let ((,resource­string
(allocate­resource­string :size ,size)))
,@body
(free­resource­string ,resource­string)))
97
When to use macros
• You have to use macros when
– you need to control evaluation
• binding (like local variables in LET)
• conditional evaluation (like AND or OR or IF)
• looping (like DO)
• Simplification without a function call (like (SETF CAR)
expanding into RPLACA)
• You can use macros to
– do computation at compile­time
– expand in place and avoid a function call
– save typing or code duplication, and to clarify code
98
Problems with using Macros
• You cannot use a macro if you have to funcall or
apply it
• Macro definitions are harder to read
• Macro definitions can be harder to debug
– The code you see in the backtrace may bear little
resemblance to your source code
• Although macros can expand recursively into other
macros, you can’t usually write a recursive
algorithm with them.
99
Redefining Macros
• Code for macro expansion captured in compiled
files of callers of the macro
• If you change the definitions of the macro itself,
you have to recompile the callers
• Defsystem tool allows you to record these
dependencies once
100
learning more
• A lot of Common Lisp is really implemented as
macros
• Looking at the expansions of these can teach you a
lot about how macros work
• (pprint (macroexpand­1 ‘(defun foo (a) (+ a 1))))
101
Allegro CL Certification
Program
Lisp Programming Series Level 2
Session 2.1.5
Macro Pitfalls and Issues
102
A Macro is not a Function
• (apply #’when (> x 3) (print x))
– This is an error
103
Macro Recursion is not like
Function Recursion
(defmacro nth* (n list)
`(if (= ,n 0) (car ,list)
(nth* (­ ,n 1) (cdr ,list))))
• macroexpanding nth* will macroexpand
forever when compiled in a function like
(defun foo (x l) (nth* x l))
• Think of the code you want the macro to
expand into
104
Valid Macro Recursion
(defmacro or* (&body body)
(cond ((null body) 'nil)
((null (cdr body)) (car body))
(t (let ((temp (gensym)))
`(let ((,temp ,(car body)))
(if ,temp ,temp
(or* ,@(cdr body))))))))
• (or* a b) expands into
(let ((#:g24 a))
(if #:g24 #:g24 b))
105
Multiple Evaluation
This definition of OR evaluates A twice
(defmacro or* (a b)
`(if ,a ,a ,b))
Do it this way instead
(defmacro or* (a b)
`(let ((temp ,a)) (if temp temp ,b)))
106
Order of Evaluation
• Evaluation order should be left to right
(defmacro and* (a b)
`(let ((temp2 ,b) (temp1 ,a))
(if (not temp1) nil
(if (not temp2) nil temp2))))
(and* (setq x 2) (setq x 3))
;; Returns 3 but x is 2!
107
Avoid Destroying Arg Lists
(defmacro sum­plus­1 (&rest args)
(cons '+ (nconc args (list 1))))
(defun foo () (sum­plus­1 2 3))
(foo) returns 6
(foo) returns 7
(foo) returns 8
• Because the macro is destructively modifying
the source code of the caller
• The source code stops changing
when you compile it
108
Variable Capture
• Using the OR* macro from a few slides back…
(setq x nil)
(let ((temp 7))
(or* x (+ temp 1)))
• This code attempts to add NIL to 1
• Because the macroexpansion of OR* causes
TEMP to get rebound to NIL
109
Global Variable Capture
(defvar width 5) ; global variable
(defmacro notice­width (w)
`(setq width ,w))
(defun draw­rectangle (x y width height)
(notice­width width)
(notice­height height)
. . .)
• The macro does not affect the global
variable as intended
110
Avoiding Global Variable Capture
• (defvar *width* 5)
• Use naming conventions that distinguish
local from global variables.
111
Avoiding Variable Capture with
Gensym
(defmacro or* (a b)
(let ((symbol (gensym)))
`(let ((,symbol ,a))
(if ,symbol ,symbol ,b))))
112
Avoiding Variable Capture with
Scope
(defmacro sum­squares­w (x y)
`(let* ((x0 ,x) ; WRONG (X0 captured)
(y0 ,y) ; problem occurs in this line
(x2 (* x0 x0)) ;; if form y refers
(y2 (* y0 y0))) ;; to x0
(+ x2 y2)))
(defmacro sum­squares­r (x y)
`(let ((x0 ,x) ; RIGHT
(y0 ,y))
(let ((x2 (* x0 x0))
(y2 (* y0 y0)))
(+ x2 y2))))
113
Variable capture example
(let ((x0 5))
(* (sum­squares­w
1 (­ (setq x0 10) 9)) x0))
505
(let ((x0 5))
(* (sum­squares­r
1 (­ (setq x0 10) 9)) x0))
20
114
SETF: a special kind of macro
> (setq a nil) ; setq only for symbols
a
> (setf a '(one two three)) ; setf of a symbol
(ONE TWO THREE)
> (setf (first a) 1) ; setf of a "place"
1
> A ; list was permanently changed
(1 2 3)
115
Builtin SETF operations
• Lisp knows how to use SETF with many
things (but not everything)
– Lists: first, second, elt, nth, car, cdr
– Arrays: aref
– Objects: slot­value
– Bits: ldb
– Hash tables: gethash
116
Rolling Your Own
• Define your own SETF procedures in one of
two ways:
• By functions and methods:
(defmethod (setf x) (new (object point))
(setf (slot­value object 'x) new))
• By defsetf macros (next slide)
117
Using DEFSETF
(defsetf car (x) (new)
`(progn (rplaca ,x ,new) ,new))
(defsetf x (point) (new)
`(setf (aref ,point 1) ,new))
118
Allegro CL Certification
Program
Lisp Programming Series Level 2
Session 2.1.6
Closures
119
What Are Closures?
• Closures are
– Executable functions
– Objects with state
• They usually appear as lambda expressions
• Nothing like them in C, C++, Java, VB, or
any other traditional language
• They are functions with a “memory”
120
A Simple Closure
(setq closure
(let ((list '(one two three four five)))
#’(lambda () (pop list))))
⇒ #<Interpreted Closure (unnamed) @ #x2083818a>
(funcall closure)
⇒ ONE
(funcall closure)
⇒ TWO
(funcall closure)
⇒ THREE
121
What Happened?
• LAMBDA created an unnamed function
• To observe the rules of lexical scoping, the
function can continue to reference LIST even
after returning from the LET
• The function makes a “snapshot” of the
variable at the time it is evaluated
• The function carries that snapshot with it as a
segment of data
122
Another Example
(let ((list '(one two three four five)))
(setq closure1 #’(lambda () (pop list)))
(setq closure2 #’(lambda () (pop list))))
;; two closures, both with a reference to LIST
(funcall closure1)
⇒ ONE
(funcall closure2)
⇒ TWO
123
Now What Happened?
• The two closures both reference a single,
shared closure variable
• They each can see modifications that the
other closure makes
124
Implicit Closures
• Closures happen implicitly when ever a
function refers to something in the lexical
environment
> (defun add­to­list (num lst)
(mapcar #'(lambda (x) (+ x num)) lst))
ADD­TO­LIST
125
Closures and Garbage
• Note that creating a closure allocates
memory and can be a source of garbage and
slowness.
• If the closure can be allocated on the stack,
then do so using dynamic­extent.
(defun add­to­list (num list)
(labels ((adder (x) (+ x num)))
(declare (dynamic­extent #’adder))
(mapcar #’adder list)))
126
Closure Example 1
• The adder fn:
> (defun add­to­list (num lst)
(mapcar #'(lambda (x) (+ x num)) lst))
ADD­TO­LIST
> (defun make­adder (n)
#'(lambda (x) (+ x n)))
MAKE­ADDER
> (setf add5 (make­adder 5))
#<closure 1 #xDDF914>
> (setf add15 (make­adder 15))
#<closure 1 #xDE2F34>
> (funcall add5 1)
6
> (funcall add15 1)
16
127
Closure Examples 2
• Closures that share variables
> (let ((counter 0))
(defun reset ()
(setf counter 0) counter)
(defun stamp ()
(incf counter) counter))
STAMP
> (list (stamp) (stamp) (reset) (stamp))
(1 2 0 1)
128
Closure Examples 3
• Complement Example
> (defun my­complement (fn)
#'(lambda (&rest args)
(not (apply fn args))))
MY­COMPLEMENT
> (mapcar (my­complement #'oddp)
'(1 2 3 4 5 6 7 8))
(NIL T NIL T NIL T NIL T)
>
129
Cool Example
• Object­oriented programming with closures
• Invented by Guy Steele in 1976
(defun make­account (&key (balance 0.0))
"Create an ACCOUNT object with one slot, BALANCE"
#'(lambda (message &rest args)
(case message
;; Object supports three methods or messages
(:deposit (incf balance (car args)))
(:withdraw (decf balance (car args)))
(:balance balance))))
(defun send (object message &rest args)
(apply object message args))
130
Example
USER(15): (setq my­account
(make­account :balance 125.00))
#<Closure (:INTERNAL MAKE­ACCOUNT 0) @ #x208490b2>
USER(16): (send my­account :balance)
125.0
USER(17): (send my­account :deposit 10.0)
135.0
USER(18): (send my­account :balance)
135.0
131
URL for homework and slides
http://www.franz.com/lab/

More Related Content

PPT
(Ai lisp)
PPT
Advance LISP (Artificial Intelligence)
PPTX
LISP: Introduction to lisp
PPTX
LISP: Introduction To Lisp
PPTX
A brief introduction to lisp language
PPTX
AI Programming language (LISP)
PPTX
PPTX
AI UNIT-4 Final (2).pptx
(Ai lisp)
Advance LISP (Artificial Intelligence)
LISP: Introduction to lisp
LISP: Introduction To Lisp
A brief introduction to lisp language
AI Programming language (LISP)
AI UNIT-4 Final (2).pptx

Similar to Advanced features of Lisp functions Advanced features of Lisp functions (20)

PPTX
Functional Programming.pptx
PPTX
LISP:Control Structures In Lisp
PPTX
LISP: Control Structures In Lisp
PPT
Lisp and scheme i
PPT
INTRODUCTION TO LISP
PDF
Introduction To Lisp
PPTX
LISP: Data types in lisp
PPTX
LISP: Data types in lisp
PPT
Lisp, An Introduction.ppt
PPT
intro.ppt
PPT
intro.ppt
PDF
201801 CSE240 Lecture 17
KEY
Functional programming in clojure
PPTX
LISP:Program structure in lisp
PPTX
LISP: Program structure in lisp
PDF
Gentle Introduction To Lisp
PDF
Functional programming using haskell notes iitk
PPT
PPTX
Funtional Programming
Functional Programming.pptx
LISP:Control Structures In Lisp
LISP: Control Structures In Lisp
Lisp and scheme i
INTRODUCTION TO LISP
Introduction To Lisp
LISP: Data types in lisp
LISP: Data types in lisp
Lisp, An Introduction.ppt
intro.ppt
intro.ppt
201801 CSE240 Lecture 17
Functional programming in clojure
LISP:Program structure in lisp
LISP: Program structure in lisp
Gentle Introduction To Lisp
Functional programming using haskell notes iitk
Funtional Programming
Ad

Recently uploaded (20)

PDF
Embodied AI: Ushering in the Next Era of Intelligent Systems
PPTX
Road Safety tips for School Kids by a k maurya.pptx
PPTX
CH1 Production IntroductoryConcepts.pptx
PPTX
Lesson 3_Tessellation.pptx finite Mathematics
PPTX
Geodesy 1.pptx...............................................
DOCX
ASol_English-Language-Literature-Set-1-27-02-2023-converted.docx
PDF
Mohammad Mahdi Farshadian CV - Prospective PhD Student 2026
PPTX
Unit 5 BSP.pptxytrrftyyydfyujfttyczcgvcd
PPTX
Internship_Presentation_Final engineering.pptx
PPTX
bas. eng. economics group 4 presentation 1.pptx
PPTX
Foundation to blockchain - A guide to Blockchain Tech
DOCX
573137875-Attendance-Management-System-original
PDF
July 2025 - Top 10 Read Articles in International Journal of Software Enginee...
PPTX
UNIT-1 - COAL BASED THERMAL POWER PLANTS
PPTX
The-Looming-Shadow-How-AI-Poses-Dangers-to-Humanity.pptx
PPTX
CYBER-CRIMES AND SECURITY A guide to understanding
PDF
Structs to JSON How Go Powers REST APIs.pdf
PDF
Queuing formulas to evaluate throughputs and servers
PPTX
Lecture Notes Electrical Wiring System Components
PPTX
IOT PPTs Week 10 Lecture Material.pptx of NPTEL Smart Cities contd
Embodied AI: Ushering in the Next Era of Intelligent Systems
Road Safety tips for School Kids by a k maurya.pptx
CH1 Production IntroductoryConcepts.pptx
Lesson 3_Tessellation.pptx finite Mathematics
Geodesy 1.pptx...............................................
ASol_English-Language-Literature-Set-1-27-02-2023-converted.docx
Mohammad Mahdi Farshadian CV - Prospective PhD Student 2026
Unit 5 BSP.pptxytrrftyyydfyujfttyczcgvcd
Internship_Presentation_Final engineering.pptx
bas. eng. economics group 4 presentation 1.pptx
Foundation to blockchain - A guide to Blockchain Tech
573137875-Attendance-Management-System-original
July 2025 - Top 10 Read Articles in International Journal of Software Enginee...
UNIT-1 - COAL BASED THERMAL POWER PLANTS
The-Looming-Shadow-How-AI-Poses-Dangers-to-Humanity.pptx
CYBER-CRIMES AND SECURITY A guide to understanding
Structs to JSON How Go Powers REST APIs.pdf
Queuing formulas to evaluate throughputs and servers
Lecture Notes Electrical Wiring System Components
IOT PPTs Week 10 Lecture Material.pptx of NPTEL Smart Cities contd
Ad

Advanced features of Lisp functions Advanced features of Lisp functions

  • 1. 1 Allegro CL Certification Program Lisp Programming Series Level 2
  • 2. 2 Goals for Level 2 • Build on Level 1 – Assumes you can write functions, use the debugger, understand lists and list processing • Detailed Exposure To – Functions – Macros – Object­oriented programming
  • 3. 3 Format of the Course • One 2­hour presentation each week – Lecture – Question and answer – Sample code • Lecture notes available online (http://www.franz.com/lab/) • Homework • One­on­one help via email
  • 4. 4 Session 1 (today) • Advanced features of Lisp functions • Structures, Hash Tables, Bits and Bytes • Macros • Closures
  • 5. 5 Session 2 Common Lisp Object System (CLOS) • Top Ten things to do in CLOS • Classes, instances, and inheritance • Methods • Class precedence list • Programming style
  • 6. 6 Session 3 • Performance considerations with CLOS • The garbage collector • Error conditions • Using the IDE to make Windows™ windows
  • 7. 7 Homework • Lisp is best learnt by hands­on experience • Many exercises for each session • Will dedicate class time to reviewing exercises • Email instructor for one­on­one assistance doing the homework or any other questions relevant to the class – [email protected]
  • 8. 8 Getting Allegro Common Lisp • This class is based on version 6.2. • Trial version should be sufficient for this module – Download free from http://www.franz.com/ – Works for 60 days • I will be using ACL on Windows • You can use ACL on UNIX, but the development environment is different, and I won't be using it.
  • 9. 9 Allegro CL Certification Program Lisp Programming Series Level 2 Session 2.1.1 Functions
  • 10. 10 Ways to define functions • defun • lambda • flet • labels
  • 11. 11 Defun (defun double (x) "Doubles the number" (declare (fixnum x)) (+ x x)) (defun fn­name arglist optional­doc­string optional­declarations code)
  • 12. 12 Argument List • Contains names for variables • that get their values from arguments provided in calls to the function • persist throughout the body of the function • are not typed • May contain optional and keyword arguments
  • 13. 13 Keyword Arguments (defun print­array­size (array &key (stream *standard­output*) UseGraphics) (let ((size (length array))) (if UseGraphics (drawsize size stream) ; then (print size stream)) ; else size))) • Call the function like this: – (print­array­size *my­array*) • Or like this: – (print­array­size *my­array* :stream my­open­file)
  • 14. 14 Keyword Arguments • Call the function with any number of the keyword arguments, in any order • Arguments specified as name/value pairs – :stream my­open­file • Costs a couple microseconds – Because Lisp must parse the argument list • Use when some arguments are only rarely needed – Source code in callers is greatly simplified • Or when different calls will need different groups of arguments
  • 15. 15 Keyword Detail &key (stream *standard­output*) UseGraphics • &key specifies the arguments that follow are keyword arguments • Each argument can either be a two­element list, a three­element list, or a single symbol – Three­element list is used for supplied­p arguments, described later on • Default value of an argument, when not passed by the caller, is the second element of the two­element list, or NIL if not otherwise specified
  • 16. 16 Optional Arguments (defun print­array­size (array &optional (stream *standard­output*) UseGraphics) (let ((size (length array))) (if UseGraphics (drawsize size stream) ; then (print size stream)) ; else size))) • Call the function like this: – (print­array­size *my­array*) • Or like this: – (print­array­size *my­array* my­open­file)
  • 17. 17 Optional Arguments • Call the function with any number of the optional arguments • Lisp determines which one is which by position – To specify the second optional argument, you must always specify the first as well • Costs a couple microseconds – Because Lisp must parse the argument list • Use when some arguments are only rarely needed, and when there aren't very many of them – Source code in callers is greatly simplified
  • 18. 18 Other possibilities (defun incr (n &optional inc) ;; if the value of inc was not specified, ;; or if it was specified but not a number, ;; then set it to 1. (if (not (numberp inc)) (setq inc 1)) (+ n inc)) (defun incr (n &optional (inc 1 increment­p)) ;; increment­p TRUE when argument was specified ;; by caller (if (and increment­p (not (numberp inc))) (print "non­numeric increment")) (+ n inc))
  • 19. 19 Optional and Keyword Arguments • Ways to specify the argument • <name> ­­ defaults to nil • (<name> <default value>) • (<name> <default value> <supplied­p>) • Use optionals for small numbers of non­ required arguments that are easy to remember • Use keywords with either large numbers of non­required arguments or ones that are hard to remember
  • 20. 20 &rest example (defun add (&rest numbers) (let ((sum 0)) (dolist (n numbers) (setq sum (+ sum n))) sum)) • Call it this way: • (add 1 2 4) • Or this way: • (add 9 1 8 4 8 6)
  • 21. 21 &rest Arguments • Caller may pass any number of arguments, there is no limit • Lisp combines all the arguments into a single list • Needed only rarely • Generally used when all the arguments have the same type and will participate equally in the operation
  • 22. 22 Pointers to Functions • The usual way of calling a function: – (+ 3 4) • Alternative way: – (funcall #'+ 3 4) • #'+ is a pointer to the function "+" • Function pointers can be passed as arguments, returned from functions, or stored as data
  • 23. 23 Pointers to Functions • #’add – Is a reference to the function named ADD (defun combiner (n) (if (typep n 'list) #'list #'+)) ;; Example of returning a function pointer ;; from a function. (setq *combiner* (combiner 3))
  • 24. 24 Calling a Function by its Pointer • #'+ – #<FUNCTION +> • (funcall #'+ 3 4 5 6) – 18 • (apply #'+ (list 3 4 5 6)) – 18
  • 25. 25 Using Function References • Functions can be used just like any other type object (defun combiner (x) (typecase x (number #'+) (list #'append) (t #'list))) COMBINER USER(49): (defun combine (&rest args) (apply (combiner (first args)) args)) COMBINE USER(50): (combine 2 3) 5 USER(51): (combine '(a b) '(c d)) (A B C D) USER(54): (combine 'a 'b 'c) (A B C)
  • 26. 26 Function References • Commonly used in sorting routines – (sort '(5 1 4 6) #'<) – #'< small numbers first – #'> big numbers first – #'string< A before Z – #'string> Z before A • Often used when mapping over a collection (vector, list, hash table, etc.) – (mapcar #'print '(5 1 4 6))
  • 27. 27 Lambdas • Nameless fns • (setq function #'(lambda (x y) (* x y))) • (setq function #'(lambda (x y) (+ x y))) • (funcall function 3 4)
  • 28. 28 Lambda ­ Example • Example (defun increment­all (&rest numbers) (mapcar #'(lambda (x) (+ x 1)) numbers)) • (increment­all 5 6 7 8) • (6 7 8 9)
  • 29. 29 Where do you use lambdas • When a function will have only one caller and it is relatively trivial • Saves using up you namespace • Seeing the code in place may improve readability in some situations • Commonly used with mapping functions
  • 30. 30 Other Functions of Functions • Many tools available to investigate your environment
  • 31. 31 fboundp • Determines if a symbol is associated with a function definition or function binding (fboundp 'double) #<Interpreted Function DOUBLE>
  • 32. 32 fdefinition • (fdefinition '+) retrieves the function object associated with the argument. Same as symbol­function for symbols, but also works on names that are lists (such as (setf foo)). • Function­lambda­expression retrieves the definition, if it is available (but the argument must be a function object, not a function name)
  • 33. 33 fmakunbound • (fmakunbound 'add) • makes the function named ADD become undefined • analogous to makunbound for variables
  • 34. 34 Symbol­function • Returns a symbol’s fn • Note: you can also setf this > (setf (symbol­function 'double) #'(lambda (x) (+ x x))) #<Interpreted Function DOUBLE> > (double 5) 10
  • 35. 35 Global .vs. Local Functions • Defun’s are global • Lambda’s can only be used in place unless the are assigned or stored on something • flets and labels can be used to create fns that are only available in a local context
  • 36. 36 Local Functions ­ labels • Enables you to define a function and use it within the scope of the labels • Think of it like a let* for functions (defun test­3rd () (labels ((3rd (lst) (first (rest (rest lst))))) (print (3rd '(1 2 3 4))) (print (3rd '(a b c d)))))
  • 37. 37 SETF Functions • setf is useful when you have a pair of operations for getting and setting a value • In other languages, you would name the pair Get­xxx and Set­xxx • With setf, you have only one name • (first list) ; gets first element of list • (setf (first list) 17) ; sets first element to 17
  • 38. 38 SETF Function Definition ;;; Get the first element (defun 1st (list) (car list)) ;;; Set the first element (defun (setf 1st) (new list) (rplaca list new) new)
  • 39. 39 Using SETF (setq a '(one two three)) (1st a) ­> ONE (setf (1st a) 1) ­> 1 (1st a) ­> 1 a ­> (1 two three)
  • 40. 40 Many Operations in Lisp itself are setf­enabled • first, second, third, last, nth, elt • aref, fill­pointer • Elements or fields of a structure • Elements or slots of a CLOS instance • symbol­value, symbol­function • gethash
  • 41. 41 The Idea of Mapping Functions • You pass a “pointer to a function” as one of the arguments • The “pointer to a function” is applied to each element of a collection • The results of the individual calls may be collected up into a list
  • 42. 42 mapcar • (mapcar fn list &rest more­lists) • Example: > (mapcar #'print '(a b c)) A B C (A B C) > (mapcar #'cons '(a b c) '(1 2 3)) ((A . 1) (B . 2) (C . 3))
  • 43. 43 maphash • (maphash function hash­table) – Hash tables covered in more detail later (maphash #'(lambda (key value) (format t "~&k=~A,v=~A" key value) ht)
  • 44. 44 The Idea of Multiple Values • Sometimes you want a function to return more than one value • Option 1: Make an object that contains the values – (defun foo () (list 1 2)) • Option 2: Use Lisp multiple values – (defun foo () (values 1 2)) – 1 is said to be the “first value” – 2 is said to be the “second value”
  • 45. 45 multiple­value­setq • Use it like setq to capture multiple values (let ((x 0)(y 0)) (print x) (print y) ; values before (multiple­value­setq (x y) (foo)) (print x) (print y) ; values after )
  • 46. 46 Multiple­Value­Bind • Use it like let or let* to capture multiple values in new local variables (multiple­value­bind (left right) (foo) (print left) (print right))
  • 47. 47 Allegro CL Certification Program Lisp Programming Series Level 2 Session 2.1.2 Structures and Hash Tables
  • 48. 48 User­defined structures • Can either use CLOS instances or defstructs – both store data in a user­defined form – instances can have behavior in addition – defstructs are more efficient, but less powerful • Designed to look similar in code – slot references look like function calls – can switch between them during development
  • 49. 49 Structures • Define with defstruct • create one with (make­<name> …) • access slot with <name>­<slotname> > (defstruct route­segment node­number start end) ROUTE­SEGMENT > (setf rs (make­route­segment :node­number 5 :start 2 :end 7)) #S(ROUTE­SEGMENT NODE­NUMBER 5 START 2 END 7) > (route­segment­start rs) 2
  • 50. 50 defstruct with default values • Example > (defstruct point (x 0) (y 0)) POINT > (setf pt (make­point)) #S(POINT X 0 Y 0)
  • 51. 51 Structures • Standard Lisp Structures are really just vectors. • Accessing an element of a structure is as fast as accessing an element of an array. • The reader functions generated by defstruct get compiled into an vector access of a specific position (fast!) • If you redefine the positions, you have to recompile your code
  • 52. 52 defstruct with type • Example > (defstruct (point (:type list)) (x 0) (y 0)) POINT > (setf pt (make­point :x 10 :y 20)) (10 20)
  • 53. 53 defstruct with type and name • Example > (defstruct (point (:type list) (:named t)) (x 0) (y 0)) POINT > (setf pt (make­point :x 10 :y 20)) (POINT 10 20)
  • 54. 54 Hash tables • Pair­oriented: Associate keys with values, just like alists and plists • Could use lists for small ones, but search time grows proportional to size of list • hash table computes hash function to use as index – speed largely independent of size • have to build your own in many other languages
  • 55. 55 Hash table examples > (setf ht (make­hash­table)) #<HASH­TABLE #xDD7410> > (gethash 'color ht) NIL NIL > (setf (gethash 'color ht) 'brown) BROWN > (gethash 'color ht) BROWN T
  • 56. 56 gethash’s Multiple values • gethash returns two values – value associated with key or NIL – Whether or not the value was found • Second value helps you distinguish between – NIL as the value of the key – NIL as the value you get when the key has no value
  • 57. 57 Hash Table Fns • Examples > (hash­table­p ht) (#<STRUCTURE­CLASS HASH­TABLE #x891668>) > (gethash 'color ht) BROWN T > (remhash 'color ht) T > (gethash 'color ht) NIL NIL
  • 58. 58 clrhash • Examples: (setf ht (make­hash­table)) #<HASH­TABLE #xE02D8C> > (setf (gethash 'color ht) 'brown) BROWN > (gethash 'color ht) BROWN T > (clrhash ht) #<HASH­TABLE #xDD8280>
  • 59. 59 Hash table iteration example (let ((test (make­hash­table))) (setf (gethash 'a test) "This is the a value") (setf (gethash 'b test) "This is the b value") (maphash #’(lambda (sym str) (format t "~&~A = ~S" sym str)) test)) B = "This is the b value" A = "This is the a value" NIL
  • 60. 60 maphash • Iterate over the contents of the hash table, pair by pair • (maphash #'(lambda (key value) ..code..) hash)
  • 61. 61 Allegro CL Certification Program Lisp Programming Series Level 2 Session 2.1.3 Bits and Bytes
  • 62. 62 Bits and Bytes • Normally represented as lisp integers • Often used for efficiency – Speed: some operations may compile into a single machine instruction – Size: a bit vector is much smaller than a general vector • Often used in combination with foreign function calls – Arguments to C++ and WIN32 libraries are often several "flags" passed as a single integer
  • 63. 63 Bits of Integers • The #b prefix means a binary notation USER(1): #b10 2 ; decimal integer 2 USER(2): *print­base* 10 ; numbers normally print in decimal USER(3): (let ((*print­base* 2)) (print #b10) nil) 10 ; decimal integer 2 printed in binary NIL USER(4):
  • 64. 64 Bit Combination • Inclusive OR of bits USER(1): (logior #b100 #b110) #b110 • AND of bits USER(1): (logand #b100 #b110) #b100 • Less commonly: logxor, logeqv, lognand, lognor, logandc1, logandc2, logorc1, logorc2
  • 65. 65 Bit Testing • (defvar *mask* #b1010) • (logtest flags *mask*) – True if the second or fourth bit in FLAGS is “on” • (logbitp 1 flags ) – True if the second bit in FLAGS is “on” • (logcount flags) – Counts the number of bits that are “on”
  • 66. 66 Byte Manipulation with ldb • USER(1): (setq flags #b111000111) • USER(2): (ldb (byte 4 0) flags) • #b0111 ; lowest (rightmost) four bits • USER(3): (ldb (byte 4 4) flags) • #b1100 ; next four bits • USER(4): (ldb (byte 8 0) flags) • #b11000111 ; lowest eight bits
  • 67. 67 Byte Manipulation USER(5): (setf (ldb (byte 4 4) flags) #b0011) USER(6): flags #b100110111 • This line modifies the second four bits of the bit field.
  • 68. 68 Shift Operation • ash ­­ arithmetic shift (left) – (ash 1 10) ­­> 1024 – (ash 255 ­6) ­­> 3 • Note that there is no assumption of integer size. You eventually get a bignum if you keep shifting left.
  • 69. 69 How Many Bits? • (integer­length #b1000) => 4 • Use it to print a binary number: (defun binary­to­string (bits) (let* ((L (integer­length bits)) (string (make­string L :initial­element #0))) (dotimes (I L) ;; Note that bit zero is on the right ;; of the string (character L­1). (when (logbitp (­ L I 1) bits) (setf (char string I) #1))) string))
  • 70. 70 Vectors of Bits (setq vector (make­array 1024 :element­type ‘bit :initial­element 0)) ;; Access and modify as any vector or array (setf (aref vector 0) 1) ;; But elements must be either zero or one (setf (aref vector 0) 2) ; ERROR
  • 71. 71 Allegro CL Certification Program Lisp Programming Series Level 2 Session 2.1.4 Macros
  • 72. 72 What are Macros? • Macros take lisp code as input and return lisp code as output. For example, When evaluating: (incf x) Evaluate this instead: (setf x (+ 1 x)) (defmacro incf (place) (list 'setf place (list '+ 1 place)))
  • 73. 73 Macroexpansion • When the evaluator sees (incf a) – It notices that INCF names a macro – It “runs” or macroexpands the macro, which transforms the line of code into: • (setf a (+ 1 a)) – It evaluates that expression instead – So when you type (incf a) to the lisp listener, it is as if you had typed (setf a (+ 1 a))
  • 74. 74 Macro Evaluation is Different • for functions – gets the function name – evaluates all the args – applies the function to the eval’ed args • for macros – passes arguments without evaluating them – the macro function returns another expression – evaluator evaluates that expression instead of the original
  • 75. 75 Recursive Macros • Macros can macroexpand into other macros • For example – WHEN macroexpands into COND – COND macroexpands into IF • The evaluator (and the compiler) recursively macroexpand an expression until there are no more macros left
  • 76. 76 Macroexpand function • macroexpand is function which lisp uses to call macro function and get result – it keeps recursively macro­expanding till no macros are left • macroexpand­1 just does one step of macroexpansion • (macroexpand­1 '(incf x)) – (setq x (+ x 1))
  • 77. 77 macro functions • stored in same function cell of symbol • stored in a different format so that the system can tell it is a macro function • macro­function <symbol> will return nil if the symbol has a normal function definition or none, but will return the expansion function if the symbol names a macro
  • 78. 78 Macro Examples • Macros are just functions that transform expressions • Use macroexpand­1 to see definition > (defmacro nil! (x) (list 'setf x nil)) NIL! > (setq x 5) 5 > (nil! x) NIL > x NIL > (macroexpand­1 '(nil! x)) (SETF X NIL)
  • 79. 79 Backquote • Used extensively in macros • Used by itself is equivalent to quote • Protects args from evaluation • comma (,) will unprotect > (setq a 1 b 2) 2 > `(a is ,a b is ,b) (A IS 1 B IS 2)
  • 80. 80 Backquote example (defmacro incf (place) `(setf ,place (+ 1 ,place))) • Compared to earlier definition of INCF, this version is shorter, more concise, and easier to understand (but equivalent) (defmacro incf (place) (list 'setf place (list '+ 1 place)))
  • 81. 81 ,@ • Like comma but splices in list > (setq lst '(1 2 3 4)) (1 2 3 4) > `(here are the numbers ,@lst) (HERE ARE THE NUMBERS 1 2 3 4)
  • 82. 82 &body • &body is like &rest, but typically reserved for macros • Example: WITH (shorthand for LET, use it to create one local variable) (defmacro with ((var &optional val) &body body) `(let ((,var ,val)) ,@body)) (with (a) (print a)) ;; this example transforms into: (let ((a nil)) (print a))
  • 83. 83 with­open­file example More complex example. There is a built­in lisp macro of the same name that does almost exactly this. (defmacro with­open­file ((var &rest args) &body body) `(let ((,var (open ,@args))) ; open file (unwind­protect (progn ,@body) ; execute body (when (streamp ,var) (close ,var)))) ; close • unwind­protect is talked about later on, but it ensures the file is closed even if an error occurs
  • 84. 84 Macro Examples • Ordered­bounds (defmacro order­bounds (left bottom right top) `(progn (if (> ,left ,right) (rotatef ,left ,right)) (if (> ,bottom ,top) (rotatef ,bottom ,top)))) (setq left 10) (setq right 0) (setq top 50) (setq bottom 4) (order­bounds left bottom right top) ;; Now LEFT is 0, RIGHT is 10, ;; TOP is 4, BOTTOM is 50
  • 85. 85 Macro Examples • Add onto the end of the list (defmacro push­last (item list) `(setf ,list (nconc ,list (list ,item))))
  • 86. 86 Macro Examples • Atomic Operations (defmacro atomic­pop (list) `(without­interrupts (pop ,list))) (defmacro atomic­push (item list) `(without­interrupts (push ,item ,list)))
  • 87. 87 Iteration Macro (defmacro while (test &body body) `(do () ((not ,test)) ,@body)) ;; Prints even numbers (setq I 0) (while (< I 10) (print I) (incf I 2))
  • 88. 88 Macro Argument Lists • Use of &key, &optional, &rest is common in macros (defmacro with­resource­string ((resource­string &key (size 80)) &body body) `(let ((,resource­string (allocate­resource­string :size ,size))) ,@body (free­resource­string ,resource­string)))
  • 89. 89 Macros with Logic • A macro need not be just a backquoted list • A macro is an arbitrarily complex function for transforming one expression into another (defmacro incf (place) (if (symbolp place) `(setq ,place (+ 1 ,place)) `(setf ,place (+ 1 ,place))))
  • 90. 90 Macro writing problems • A macro is not a function – Certain uses are not allowed • multiple evaluation problem – Inadvertently evaluate args multiple times • variable capture problem – Inadvertently shadow a variable name
  • 91. 91 Macros are not Functions • (apply #’when (> x 3) x) – This is an error because APPLY only works on functions
  • 92. 92 Don’t evaluate more than once • A macro similar to OR (defmacro or1 (a b) `(if ,a ,a ,b)) • What happens for: (or1 (print 1) (print 2)) (if (print 1) (print 1) (print 2)) • To avoid multiple evaluation: (defmacro or2 (a b) `(let ((temp ,a)) (if temp temp ,b)))
  • 93. 93 Variable Capture • How would you implement Lisp’s OR macro? (defmacro or2 (a b) `(let ((temp ,a)) (if temp temp ,b))) (let ((x nil) (temp 7)) (or2 x temp)) ;; Returns NIL (there are two TEMPs)
  • 94. 94 Generate symbols that can’t be captured • Gensym (defmacro or3 (a b) (let ((symbol (gensym))) `(let ((,symbol ,a)) (if ,symbol ,symbol ,b))))
  • 95. 95 Turning Functions into Macros • Do it to eliminate a function call • Do it when the function is not recursive (defun second (x) (cadr x)) (defmacro second (x) `(cadr ,x)) (defun sum (&rest numbers) (apply #’+ numbers)) (defmacro sum (&rest numbers) `(+ ,@numbers))
  • 96. 96 When to Use Macros • Macros help avoid code duplication (defmacro with­resource­string ((resource­string &key (size 80)) &body body) `(let ((,resource­string (allocate­resource­string :size ,size))) ,@body (free­resource­string ,resource­string)))
  • 97. 97 When to use macros • You have to use macros when – you need to control evaluation • binding (like local variables in LET) • conditional evaluation (like AND or OR or IF) • looping (like DO) • Simplification without a function call (like (SETF CAR) expanding into RPLACA) • You can use macros to – do computation at compile­time – expand in place and avoid a function call – save typing or code duplication, and to clarify code
  • 98. 98 Problems with using Macros • You cannot use a macro if you have to funcall or apply it • Macro definitions are harder to read • Macro definitions can be harder to debug – The code you see in the backtrace may bear little resemblance to your source code • Although macros can expand recursively into other macros, you can’t usually write a recursive algorithm with them.
  • 99. 99 Redefining Macros • Code for macro expansion captured in compiled files of callers of the macro • If you change the definitions of the macro itself, you have to recompile the callers • Defsystem tool allows you to record these dependencies once
  • 100. 100 learning more • A lot of Common Lisp is really implemented as macros • Looking at the expansions of these can teach you a lot about how macros work • (pprint (macroexpand­1 ‘(defun foo (a) (+ a 1))))
  • 101. 101 Allegro CL Certification Program Lisp Programming Series Level 2 Session 2.1.5 Macro Pitfalls and Issues
  • 102. 102 A Macro is not a Function • (apply #’when (> x 3) (print x)) – This is an error
  • 103. 103 Macro Recursion is not like Function Recursion (defmacro nth* (n list) `(if (= ,n 0) (car ,list) (nth* (­ ,n 1) (cdr ,list)))) • macroexpanding nth* will macroexpand forever when compiled in a function like (defun foo (x l) (nth* x l)) • Think of the code you want the macro to expand into
  • 104. 104 Valid Macro Recursion (defmacro or* (&body body) (cond ((null body) 'nil) ((null (cdr body)) (car body)) (t (let ((temp (gensym))) `(let ((,temp ,(car body))) (if ,temp ,temp (or* ,@(cdr body)))))))) • (or* a b) expands into (let ((#:g24 a)) (if #:g24 #:g24 b))
  • 105. 105 Multiple Evaluation This definition of OR evaluates A twice (defmacro or* (a b) `(if ,a ,a ,b)) Do it this way instead (defmacro or* (a b) `(let ((temp ,a)) (if temp temp ,b)))
  • 106. 106 Order of Evaluation • Evaluation order should be left to right (defmacro and* (a b) `(let ((temp2 ,b) (temp1 ,a)) (if (not temp1) nil (if (not temp2) nil temp2)))) (and* (setq x 2) (setq x 3)) ;; Returns 3 but x is 2!
  • 107. 107 Avoid Destroying Arg Lists (defmacro sum­plus­1 (&rest args) (cons '+ (nconc args (list 1)))) (defun foo () (sum­plus­1 2 3)) (foo) returns 6 (foo) returns 7 (foo) returns 8 • Because the macro is destructively modifying the source code of the caller • The source code stops changing when you compile it
  • 108. 108 Variable Capture • Using the OR* macro from a few slides back… (setq x nil) (let ((temp 7)) (or* x (+ temp 1))) • This code attempts to add NIL to 1 • Because the macroexpansion of OR* causes TEMP to get rebound to NIL
  • 109. 109 Global Variable Capture (defvar width 5) ; global variable (defmacro notice­width (w) `(setq width ,w)) (defun draw­rectangle (x y width height) (notice­width width) (notice­height height) . . .) • The macro does not affect the global variable as intended
  • 110. 110 Avoiding Global Variable Capture • (defvar *width* 5) • Use naming conventions that distinguish local from global variables.
  • 111. 111 Avoiding Variable Capture with Gensym (defmacro or* (a b) (let ((symbol (gensym))) `(let ((,symbol ,a)) (if ,symbol ,symbol ,b))))
  • 112. 112 Avoiding Variable Capture with Scope (defmacro sum­squares­w (x y) `(let* ((x0 ,x) ; WRONG (X0 captured) (y0 ,y) ; problem occurs in this line (x2 (* x0 x0)) ;; if form y refers (y2 (* y0 y0))) ;; to x0 (+ x2 y2))) (defmacro sum­squares­r (x y) `(let ((x0 ,x) ; RIGHT (y0 ,y)) (let ((x2 (* x0 x0)) (y2 (* y0 y0))) (+ x2 y2))))
  • 113. 113 Variable capture example (let ((x0 5)) (* (sum­squares­w 1 (­ (setq x0 10) 9)) x0)) 505 (let ((x0 5)) (* (sum­squares­r 1 (­ (setq x0 10) 9)) x0)) 20
  • 114. 114 SETF: a special kind of macro > (setq a nil) ; setq only for symbols a > (setf a '(one two three)) ; setf of a symbol (ONE TWO THREE) > (setf (first a) 1) ; setf of a "place" 1 > A ; list was permanently changed (1 2 3)
  • 115. 115 Builtin SETF operations • Lisp knows how to use SETF with many things (but not everything) – Lists: first, second, elt, nth, car, cdr – Arrays: aref – Objects: slot­value – Bits: ldb – Hash tables: gethash
  • 116. 116 Rolling Your Own • Define your own SETF procedures in one of two ways: • By functions and methods: (defmethod (setf x) (new (object point)) (setf (slot­value object 'x) new)) • By defsetf macros (next slide)
  • 117. 117 Using DEFSETF (defsetf car (x) (new) `(progn (rplaca ,x ,new) ,new)) (defsetf x (point) (new) `(setf (aref ,point 1) ,new))
  • 118. 118 Allegro CL Certification Program Lisp Programming Series Level 2 Session 2.1.6 Closures
  • 119. 119 What Are Closures? • Closures are – Executable functions – Objects with state • They usually appear as lambda expressions • Nothing like them in C, C++, Java, VB, or any other traditional language • They are functions with a “memory”
  • 120. 120 A Simple Closure (setq closure (let ((list '(one two three four five))) #’(lambda () (pop list)))) ⇒ #<Interpreted Closure (unnamed) @ #x2083818a> (funcall closure) ⇒ ONE (funcall closure) ⇒ TWO (funcall closure) ⇒ THREE
  • 121. 121 What Happened? • LAMBDA created an unnamed function • To observe the rules of lexical scoping, the function can continue to reference LIST even after returning from the LET • The function makes a “snapshot” of the variable at the time it is evaluated • The function carries that snapshot with it as a segment of data
  • 122. 122 Another Example (let ((list '(one two three four five))) (setq closure1 #’(lambda () (pop list))) (setq closure2 #’(lambda () (pop list)))) ;; two closures, both with a reference to LIST (funcall closure1) ⇒ ONE (funcall closure2) ⇒ TWO
  • 123. 123 Now What Happened? • The two closures both reference a single, shared closure variable • They each can see modifications that the other closure makes
  • 124. 124 Implicit Closures • Closures happen implicitly when ever a function refers to something in the lexical environment > (defun add­to­list (num lst) (mapcar #'(lambda (x) (+ x num)) lst)) ADD­TO­LIST
  • 125. 125 Closures and Garbage • Note that creating a closure allocates memory and can be a source of garbage and slowness. • If the closure can be allocated on the stack, then do so using dynamic­extent. (defun add­to­list (num list) (labels ((adder (x) (+ x num))) (declare (dynamic­extent #’adder)) (mapcar #’adder list)))
  • 126. 126 Closure Example 1 • The adder fn: > (defun add­to­list (num lst) (mapcar #'(lambda (x) (+ x num)) lst)) ADD­TO­LIST > (defun make­adder (n) #'(lambda (x) (+ x n))) MAKE­ADDER > (setf add5 (make­adder 5)) #<closure 1 #xDDF914> > (setf add15 (make­adder 15)) #<closure 1 #xDE2F34> > (funcall add5 1) 6 > (funcall add15 1) 16
  • 127. 127 Closure Examples 2 • Closures that share variables > (let ((counter 0)) (defun reset () (setf counter 0) counter) (defun stamp () (incf counter) counter)) STAMP > (list (stamp) (stamp) (reset) (stamp)) (1 2 0 1)
  • 128. 128 Closure Examples 3 • Complement Example > (defun my­complement (fn) #'(lambda (&rest args) (not (apply fn args)))) MY­COMPLEMENT > (mapcar (my­complement #'oddp) '(1 2 3 4 5 6 7 8)) (NIL T NIL T NIL T NIL T) >
  • 129. 129 Cool Example • Object­oriented programming with closures • Invented by Guy Steele in 1976 (defun make­account (&key (balance 0.0)) "Create an ACCOUNT object with one slot, BALANCE" #'(lambda (message &rest args) (case message ;; Object supports three methods or messages (:deposit (incf balance (car args))) (:withdraw (decf balance (car args))) (:balance balance)))) (defun send (object message &rest args) (apply object message args))
  • 130. 130 Example USER(15): (setq my­account (make­account :balance 125.00)) #<Closure (:INTERNAL MAKE­ACCOUNT 0) @ #x208490b2> USER(16): (send my­account :balance) 125.0 USER(17): (send my­account :deposit 10.0) 135.0 USER(18): (send my­account :balance) 135.0
  • 131. 131 URL for homework and slides http://www.franz.com/lab/