macros and general code walkers in lisp: how useful! or, how useful? ernst van waning

24
Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning [email protected]

Upload: austin-harvey

Post on 18-Jan-2018

226 views

Category:

Documents


0 download

DESCRIPTION

Benelux-LispersMacros in Common Lisp3 Macros are replaced by their expansion (expansion time) The original call evaporates After expansion, their code may be evaluated (evaluation time) Macros in Lisp

TRANSCRIPT

Page 1: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Macros and general code walkers in Lisp:

how useful! or, how useful?

Ernst van [email protected]

Page 2: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 2

OverviewShort overview of macros in LispMacros transform macro callsMacros are not code transformers

In frustration I have sometimes thought macros have a certain smell

Lisp has many specific code walkersQ: can we make general code walkers?

Page 3: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 3

Macros are replaced by their expansion (expansion time)The original call evaporatesAfter expansion, their code may be evaluated (evaluation time)

Macros in Lisp

Page 4: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 4

Expansion and evaluationArguments of macro calls are not evaluatedAt expansion time, appropriate error messages do make senseEvaluation is done after the macro expanded

Page 5: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 5

Debugging macrosMacroexpand-1 expands your macro once (i.e., applies the expander once)Macroexpand expands your macro call until it is no longer a macro callWith a non-macro they just return (values form ’nil) Expanding all macros in all subforms is a different game: code walker

Page 6: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 6

Tracing expansionsUseful for debugging local macrosUseful for studying system macros

(defmacro trexp (form &environment env) (let ((*print-pretty* t)) (multiple-value-bind (expansion expanded-p) (macroexpand-1 form env) (cond (expanded-p (format *trace-output* "~&~S~%-m1->~%“

form) `(trexp ,expansion)) (t (format *trace-output* "~&~S~%~%" form) expansion)))))

Page 7: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 7

A model for macrosLisp is explained using Lisp, so we explain Lisp’s macros with Lisp

(defmacro our-expander (name) `(get ,name 'expander))

Our-expander is an accessor, i.e., it can be set with setf

Page 8: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 8

A model for macros(defun our-macro-call? (xpr)

(and (consp xpr) (our-expander (car xpr))))

(defun our-macroexpand-1 (xpr) (if (our-macro-call? xpr) (funcall (our-expander (car xpr)) xpr) xpr))

Page 9: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 9

A model for macros(defmacro our-defmacro (name args &body body)

(let ((g (gensym))) ;unique symbol `(progn (setf (our-expander ',name) ;store (lambda (,g) (block ,name ;for return-from (destructuring-bind ,args

(cdr ,g) ,@body)))) ',name)))

Page 10: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 10

A model for macrosThe actual argument to an expander is the entire macro callMacros do not evaluate the arguments of the macro callThe expander is really a function retaining its lexical environmentMacros are not first-class values

Page 11: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

What are macros good for?

Page 12: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 12

Macros control evaluationSpecial syntax

(dotimes (i 10 i) (princ i)) Implicit quoting

`(setf (our-expander ‘,name) …)Design your own control structures

(aif xpr pos zero neg)Multiple evaluations

(dotimes (i 10 i) (princ i))

Page 13: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 13

Macros compute during expansion

(defmacro avg (&rest numbers) `(/ (+ ,@numbers) ,(length numbers)))

Definers also compute during expansionDefun, defmacro, &c. do a lot of bookkeepingThink of writing your own definers!

Page 14: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 14

Macros as accessors(setf (our-expander name) new)~m~> (something like)(let ((#:g452 name)

(#:g453 'expander)(#:g455 new)) (inverse-get #:g452 #:g453 #:g455))

Setf looks “inside” its first argumentThere are many accessors with their own setf-expanders

Page 15: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 15

Macros set up lexical bindings

(dotimes (i 10 i) (princ i))

With-macroswith-open-file, with-output-to-string &c.

Do-macrosdo, dolist, dotimes, do-symbols &c.

Page 16: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

What more do we want?

Page 17: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 17

Macros as code transformers

Suppose we want to have type-strict expressions but without painA macro scalar is fine:(scalar :e) –m-> 2.718281…

But what if I want this?(scalar (exp 1))-m-> (exp (scalar 1))-m-> (exp 1d0)-m-> 2.718281… ;at expansion time

Page 18: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 18

Code transformationSums of squares of real numbers are non-negative (at least, in theory):

(scalar (sqrt ssq)) -m*-> (the (scalar 0) (sqrt (the (scalar 0) ssq)))

Can we prove that ssq is non-negative by expanding a macro?Macros do not allow arbitrary code transformations

Page 19: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 19

Domain specific extensions

Lisp is an extensible programming languageBuild applications as extensions to LispTelescoping: a strategy to automatically generate highly optimized domain specific librariesBut how easy is it to write in Lisp

domain-specific semantic checks?domain-specific optimizations?

Page 20: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 20

Term Rewriting Systems (TRS) aka Code WalkersUseful in automatic theorem provingLisp has many code walkers:

Read, eval, print, compileCross-referencers, and more…

Lisp makes it easy to write specific ones

Page 21: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 21

A general code walker in Lisp?

What is a general code walker?Minimizes effort to write specific onesTraverses all forms, a fortiori special ones…more…?

Integration with macros is possibleChange macroexpand-1

Surrounding code can be made visible by means of a stack

Page 22: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 22

A general code walker in Lisp?

The infamous 24 special forms of Lisp:Special forms implemented as macroMacros implemented as special formTraversal of implementation-specific special formsAll special forms retrievable in any Lisp

We can check if they have a walker

Page 23: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 23

A general code walker in Lisp?

What about macros?What about system-macros?What about the portability of your walkers?

Page 24: Macros and general code walkers in Lisp: how useful! or, how useful? Ernst van Waning

Benelux-Lispers Macros in Common Lisp 24

A general code walker in Lisp?

Looks like a clear idea, but is it?Even if the idea would be clear, there are real problems to solveWould it really help you write your code walkers?Specific code walkers, however, remain very useful