1 COSC3401-05-10-18 generating functions, templates, and macros Yves Lespérance Adapted from Peter Roosen- Runge
Jan 18, 2018
1COSC3401-05-10-18
generating functions, templates, and macros
Yves LespéranceAdapted from Peter Roosen-
Runge
2COSC3401-05-10-18
midterm October 20
bring photo ID closed book; no access to cellphones, PDAs, laptops, etc.
test will be based on the material in the textbook (Ch. 2-8, 10-12, 14), lectures, and readings
3COSC3401-05-10-18
constructing a pumper
Automating Ch. 11pumper will create a tail-recursive function and a main function to call it, with arguments:function name, the initial result, and a 'construction' function f
f constructs a new (partial) result from a previous (partial) result,
with the name of f = |HELP-name|
4COSC3401-05-10-18
pumper in action
Example: construct both tail-recursive rev (reverse)and its helper function(pumper 'rev NIL ; initial 'CONS ; used to construct result )
recall in rev2result --> (CONS (FIRST list) result)
5COSC3401-05-10-18
numerical example sum of squares: (sumsq list) slow version:
(+ (* (FIRST list) (FIRST list)) (sumsq (REST list))
or define sumsq and |Help-SUMSQ|(pumper
'sumsq0'(LAMBDA (x y) (+ (* x x) y))
)
6COSC3401-05-10-18
the main function
code to construct the main function(DEFUN makeMain (name helper initial)(EVAL (LIST 'DEFUN name '(arglist)
(LIST helper 'arglist initial))
))
7COSC3401-05-10-18
make the helper
(DEFUN makeHelp (helper f) (EVAL (LIST 'DEFUN helper '(arglist result)
(LIST 'IF '(ENDP arglist) 'result (LIST helper '(REST arglist) (LIST ’FUNCALL (LIST 'FUNCTION f)
(LIST 'FIRST arglist)
result))))))
8COSC3401-05-10-18
demo
>(makehelp 'helpfun 'CONS) (defun helpfun (arglist result) (if (endp arglist) result (helpfun (rest arglist) (FUNCALL (function CONS) (first arglist) result))))
9COSC3401-05-10-18
assembling the pieces
(DEFUN pumper (name initial f) (LET ((helper (INTERN (FORMAT nil "Help-~a" name))))
(makeMain name helper initial)
(makeHelp helper f) ) )
10COSC3401-05-10-18
using templates
use template for expressions involving substitutions of values for variables into a fixed structureLisp's substitution operators
backquote ` : means don’t evaluate unless specified
comma , : ,expr means evaluatesee form-cons.html
11COSC3401-05-10-18
template example
(DEFUN makeMain (name helper initial)
(EVAL ‘(DEFUN ,name (arglist) (,helper arglist ,initial)))
)
12COSC3401-05-10-18
the complete pumper
(DEFUN pumper (name initial f) (LET ((helper (INTERN (FORMAT nil "Help-~a"
name)))) (EVAL `(DEFUN ,name (arglist) (,helper
arglist ,initial))) (EVAL `(DEFUN ,helper (arglist result) (IF (ENDP arglist) result (,helper (REST
arglist) (FUNCALL (FUNCTION ,f) (FIRST arglist) result)))) ))
13COSC3401-05-10-18
pumper demo
tail-recursive reverse >(pumper 'rev NIL 'CONS)
|Help-REV| >(rev '(a b c))
(C B A) (symbol-function '|Help-REV|) = (LAMBDA-BLOCK |Help-REV| (ARGLIST RESULT) (IF (ENDP ARGLIST) RESULT (|Help-REV| (REST ARGLIST) (FUNCALL #'CONS (FIRST ARGLIST) RESULT))))
14COSC3401-05-10-18
closures
A function may be defined in one context and used in another. If it contains free variables, this may cause problems.
Lisp avoids this by keeping a record of the environment where the function was defined in a closure.
15COSC3401-05-10-18
closure e.g.
(DEFUN gen_adder (n)(FUNCTION (LAMBDA (x) (+ x n))))
(DEFUN eg (n k)(FUNCALL (gen_adder k) n))
>(eg 5 7)12
16COSC3401-05-10-18
macros
17COSC3401-05-10-18
sort of like functions, but . .
one of the most interesting but tricky aspects of Lisp.
unlike functions, macros don't evaluate their argumentsthey compute on unevaluated expressions
just uninterpreted data structures: binary trees
'dot' at the root of every sub-tree atoms at the leaves
macros can be expanded once when function that uses macros is defined or compiled
18COSC3401-05-10-18
COND is an example
>(DESCRIBE ’COND)… special operator with macro definition, has 1 property SYSTEM::MACRO.
For more information, evaluate(SYMBOL-PLIST ’COND)…
>(SYMBOL-PLIST ’COND)(SYSTEM::MACRO #<COMPILED-CLOSURE COND>)
19COSC3401-05-10-18
2-step
macro evaluation takes two steps
expansions-expression evaluation value
MACROEXPAND EVAL
>(MACROEXPAND '(COND ((NULL x) 1) ((NULL y) 2) (:OTHERWISE 3)))(IF (NULL X) 1 (IF (NULL Y) 2 (IF :OTHERWISE 3 NIL)))
20COSC3401-05-10-18
e.g. flambda
often write (FUNCTION (LAMBDA …)); define a macro flambda that abbreviates this.
(DEFMACRO flambda (&REST args) (LIST ’FUNCTION (CONS 'LAMBDA
args))) ; args will be a list
(MACROEXPAND ’(FLAMBDA (X Y) (CONS X Y)))#’(LAMBDA (X Y) (CONS X Y))
21COSC3401-05-10-18
using a template
(DEFMACRO flambda (&REST args) `(FUNCTION (LAMBDA ,args)))
22COSC3401-05-10-18
e.g. 2+
(DEFMACRO 2+ (ARG)`(1+ (1+ ,arg)))
>(MACROEXPAND ’(2+ x))(1+ (1+ x))T>(2+ (+ 3 5))10
23COSC3401-05-10-18
destructuring
Macros often destructure their arguments, i.e. extract some of their parts; this is easier if we use structured parameters, lists with named parts
>(DEFMACRO cross ((a b) (c d)) `((,a ,d) (,b ,c)))(MACROEXPAND '(cross (one two) (three four)))((one four) (two three))
24COSC3401-05-10-18
fancier example:
(DEFMACRO crossdot ((a . b) (c . d)) `((,a ,d) (,b ,c)))
(MACROEXPAND '(crossdot (one two three) (four five six)))((one (five six)) ((two three) four)
what's happening? what are a, b, c & d bound to?
25COSC3401-05-10-18
use of macros
support abstraction at little cost, e.g. get-state-field
can add abbreviations that make programming easier, e.g. COND, AND for more than 2 arguments, loop constructs, etc.
can define embedded languages within Lisp with little execution cost
caveat: user must learn the syntax expected by the macros
26COSC3401-05-10-18
macros vs. functions
a macro is treated internally as a function of one argument
order of evaluation is different, outside-in rather than inside-out, e.g.>(MACROEXPAND ’(2+ (2+ 5))(1+ (1+ (2+ 5)))T>(2+ (2+ 5))9
27COSC3401-05-10-18
more examples
seehttp://www.cs.yorku.ca/course/3401/MacroExamples.html