Use variable from outside (lexical) environment in a macro - macros

How do I get this piece of macro to function as intended? -- I'd like to capture p from the lexical environment without having to send it to the macro as an argument.
(define-syntax-rule (fi a b)
(if p a b)) ;--->capture `p` from lexical env
(let ((p #t))
(fi 1 2))
Bonus thanks -- How would I do the same in CL?

In Common Lisp a macro is simply a function that takes as input the list structure of the code and returns a list structure representing the new code.
(defmacro fi (a b)
`(if p ,a ,b))
So if you were to use fi like this:
(let ((p t)) ; Common Lisp uses 't' for truth.
(fi 1 2))
It is as if you had typed:
(let ((p t))
(if p 1 2))
To see how you would get this expansion, imagine fi was a function and you gave it the arguments of 1 and 2.
(fi 1 2) => (if p 1 2)
Then took the list structure it returned and substituted it with the call to fi.
The example you give is simple because the arguments evaluate to themselves. If you had something more complicated like the expressions (* 1 1) and (+ 1 1), the actual list structure is passed in (the value of a is the list (* 1 1), and the value of b is the list (+ 1 1))
(fi (* 1 1) (+ 1 1)) => (if p (* 1 1) (+ 1 1))

You can't capture local bindings with syntax-rules. You can use syntax-case for that, though:
(define-syntax fi
(lambda (stx)
(syntax-case stx ()
((_ a b)
(with-syntax ((p (datum->syntax stx #'p)))
#'(if p a b))))))
However, using datum->syntax to capture identifiers of a fixed name like this is not ideal. If you're using Racket, it's better to use syntax parameters for this.
For Scheme implementations that don't have syntax-case but have explicit renaming, you might write the macro this way:
(define-syntax fi
(er-macro-transformer
(lambda (exp rename compare)
`(,(rename 'if) p ,(cadr exp) ,(caddr exp)))))
Some people find it simpler, but the onus is on you to rename everything that you're not intentionally capturing. In this case, we're explicitly renaming if; for most other macros that use lambda, let, etc., those all must be renamed.

Related

How to increment a Record Field using Scheme define-syntax macro

Given a Chez Scheme record with many numeric fields that are contantly being mutated by small increments and decrements, usually by one, is there a way to write a macro that can mutate a field value by passing it the field? The way I accomplish this now is something like the following REPL transcript:
Chez Scheme Version 9.5.4
Copyright 1984-2020 Cisco Systems, Inc.
> (define-record-type r (fields (mutable x) (mutable y)
;; and so on...
))
> (define my-r (make-r 3 5
;; and so on...
))
> (r-x-set! my-r (+ (r-x my-r) 1))
> my-r
#[#{r gak6l6ll8wuv7yd61kiomgudo-2} 4 5]
It would be nice to have a simple macro, say inc!, that could do the mutating increment/decrement operations on the fields in the record. I started with something like a Scheme version of Lisps incf and decf,
(define-syntax inc!
(syntax-rules ()
((_ x) (begin (set! x (+ x 1)) x))))
(inc! (r-x my-r)) ;; Syntax error
Which works for "normal" variables (and makes it easy to implement dec!), but it doesn't use the mechanism to set mutable record fields, r-x-set! in this case.
Is there an obvious way to write such a macro? One where you can just pass a reference to the record field without having to write something different for each field?
You can construct a -set! mutator from the given accessor. This can be done by converting the symbol for the accessor to a string and appending "-set!" to it. Then eval can be used to get the actual mutator procedure. Here is a macro that increments a specified field by some amount n:
(define-syntax increment-n!
(syntax-rules ()
[(_ (acc rec) n)
(let* ((acc-name (symbol->string (quote acc)))
(mut-name (string-append acc-name "-set!"))
(mut! (eval (string->symbol mut-name))))
(mut! rec (+ (acc rec) n)))]))
This can be used to create an inc! macro:
(define-syntax inc!
(syntax-rules ()
[(_ (acc rec)) (increment-n! (acc rec) 1)]))
But, it would be nice to be able to increment multiple fields at the same time; here are inc! and dec! macros that do that:
(define-syntax inc!
(syntax-rules ()
[(_ (acc rec) ...) (begin (increment-n! (acc rec) 1) ...)]))
(define-syntax dec!
(syntax-rules ()
[(_ (acc rec) ...) (begin (increment-n! (acc rec) -1) ...)]))
Sample interaction:
> my-r
#[#{r n5an6pxs3wvid36v2gvn8z9zo-5} 3 5 7]
> (inc! (r-x my-r))
> my-r
#[#{r n5an6pxs3wvid36v2gvn8z9zo-5} 4 5 7]
> (dec! (r-z my-r))
> my-r
#[#{r n5an6pxs3wvid36v2gvn8z9zo-5} 4 5 6]
> (inc! (r-x my-r) (r-y my-r) (r-z my-r))
> my-r
#[#{r n5an6pxs3wvid36v2gvn8z9zo-5} 5 6 7]
A Note on the Use of eval
The increment-n! macro constructs a symbol which has already been bound to a mutator procedure. That symbol could then be bound to mut! directly, but then when the expression (mut! rec (+ (acc rec) n)) is evaluated an exception would be raised since mut! now evaluates to a symbol, e.g., r-x-set!. We want mut! to evaluate to a procedure in a procedure call. By calling eval on the constructed symbol first we get the mutator procedure which is bound to that symbol, binding it to mut! instead of the symbol.
Here is a REPL interaction that illustrates the problem, and will hopefully help to clarify:
> (define f (string->symbol "+"))
> f
+
> (f 1 2)
Exception: attempt to apply non-procedure +
Type (debug) to enter the debugger.
> (define f (eval (string->symbol "+")))
> f
#<procedure +>
> (f 1 2)
3

creating a macro for iterate in Common Lisp

I am trying to practise creating macros in Common Lisp by creating a simple += macro and an iterate macro. I have managed to create the += macro easily enough and I am using it within my iterate macro, which I am having a couple of issues with. When I try to run my macro with for example
(iterate i 1 5 1 (print (list 'one i)))
(where i is the control variable, 1 is the start value, 5 is the end value, and 1 is the increment value). I receive SETQ: variable X has no value
(defmacro += (x y)
(list 'setf x '(+ x y)))
(defmacro iterate (control beginExp endExp incExp &rest body)
(let ( (end (gensym)) (inc (gensym)))
`(do ( (,control ,beginExp (+= ,control ,inc)) (,end ,endExp) (,inc ,incExp) )
( (> ,control ,end) T)
,# body
)
)
)
I have tried multiple different things to fix it by messing with the , and this error makes me unsure as to whether the problem is with iterate or +=. From what I can tell += works properly.
Check the += expansion to find the error
You need to check the expansion:
CL-USER 3 > (defmacro += (x y)
(list 'setf x '(+ x y)))
+=
CL-USER 4 > (macroexpand-1 '(+= a 1))
(SETF A (+ X Y))
T
The macro expansion above shows that x and y are used, which is the error.
We need to evaluate them inside the macro function:
CL-USER 5 > (defmacro += (x y)
(list 'setf x (list '+ x y)))
+=
CL-USER 6 > (macroexpand-1 '(+= a 1))
(SETF A (+ A 1))
T
Above looks better. Note btw. that the macro already exists in standard Common Lisp. It is called incf.
Note also that you don't need it, because the side-effect is not needed in your iterate code. We can just use the + function without setting any variable.
Style
You might want to adjust a bit more to Lisp style:
no camelCase -> default reader is case insensitive anyway
speaking variable names -> improves readability
documentation string in the macro/function - improves readability
GENSYM takes an argument string -> improves readability of generated code
no dangling parentheses and no space between parentheses -> makes code more compact
better and automatic indentation -> improves readability
the body is marked with &body and not with &rest -> improves automatic indentation of the macro forms using iterate
do does not need the += macro to update the iteration variable, since do updates the variable itself -> no side-effects needed, we only need to compute the next value
generally writing a good macro takes a bit more time than writing a normal function, because we are programming on the meta-level with code generation and there is more to think about and a few basic pitfalls. So, take your time, reread the code, check the expansions, write some documentation, ...
Applied to your code, it now looks like this:
(defmacro iterate (variable start end step &body body)
"Iterates VARIABLE from START to END by STEP.
For each step the BODY gets executed."
(let ((end-variable (gensym "END"))
(step-variable (gensym "STEP")))
`(do ((,variable ,start (+ ,variable ,step-variable))
(,end-variable ,end)
(,step-variable ,step))
((> ,variable ,end-variable) t)
,#body)))
In Lisp the first part - variable, start, end, step - usually is written in a list. See for example DOTIMES. This makes it for example possible to make step optional and to give it a default value:
(defmacro iterate ((variable start end &optional (step 1)) &body body)
"Iterates VARIABLE from START to END by STEP.
For each step the BODY gets executed."
(let ((end-variable (gensym "END"))
(step-variable (gensym "STEP")))
`(do ((,variable ,start (+ ,variable ,step-variable))
(,end-variable ,end)
(,step-variable ,step))
((> ,variable ,end-variable) t)
,#body)))
Let's see the expansion, formatted for readability. We use the function macroexpand-1, which does the macro expansion only one time - not macro expanding the generated code.
CL-USER 10 > (macroexpand-1 '(iterate (i 1 10 2)
(print i)
(print (* i 2))))
(DO ((I 1 (+ I #:STEP2864))
(#:END2863 10)
(#:STEP2864 2))
((> I #:END2863) T)
(PRINT I)
(PRINT (* I 2)))
T
You can see that the symbols created by gensym are also identifiable by their name.
We can also let Lisp format the generated code, using the function pprint and giving a right margin.
CL-USER 18 > (let ((*print-right-margin* 40))
(pprint
(macroexpand-1
'(iterate (i 1 10 2)
(print i)
(print (* i 2))))))
(DO ((I 1 (+ I #:STEP2905))
(#:END2904 10)
(#:STEP2905 2))
((> I #:END2904) T)
(PRINT I)
(PRINT (* I 2)))
I figured it out. Turns out I had a problem in my += macro and a couple of other places in my iterate macro. This is the final working result. I forgot about the , while i was writing the += macro. The other macro declerations where out of order.
(defmacro += (x y)
`(setf ,x (+ ,x ,y)))
(defmacro iterate2 (control beginExpr endExpr incrExpr &rest bodyExpr)
(let ((incr(gensym))(end(gensym)) )
`(do ((,incr ,incrExpr)(,end ,endExpr)(,control ,beginExpr(+= ,control ,incr)))
((> ,control ,end) T)
,# bodyExpr
)
)
)

Difference between an implementation of 'when' as a function vs. as a macro

What exactly is different between these implementations of 'when'?
(define-syntax when
(syntax-rules ()
((_ pred b1 ...)
(if pred (begin b1 ...)))))
vs.
(define (my-when pred b1 ...)
(if pred (begin b1 ...)))
For example, when 'my-when' is used in this for loop macro:
(define-syntax for
(syntax-rules ()
((_ (i from to) b1 ...)
(let loop((i from))
(my-when (< i to)
b1 ...
(loop (+ i 1)))))))
an error occurs:
(for (i 0 10) (display i))
; Aborting!: maximum recursion depth exceeded
I do not think 'when' can be implemented as a function, but I do not know why...
Scheme has strict semantics.
This means that all of a function's parameters are evaluated before the function is applied to them.
Macros take source code and produce source code - they don't evaluate any of their parameters.
(Or, well, I suppose they do, but their parameters are syntax - language elements - rather than what you normally think of as values, such as numbers or strings. Macro programming is meta-programming. It's important to be aware of which level you're programming at.)
In your example this means that when my-when is a function, (loop (+ i 1)) must be evaluated before my-when can be applied to it.
This leads to an infinite recursion.
When it's a macro, the my-when form is first replaced with the equivalent if-form
(if (< i to)
(begin
b1 ...
(loop (+ i 1))))
and then the whole thing is evaluated, which means that (loop (+ i 1)) only gets evaluated when the condition is true.
If you implement when as a procedure like you did, then all arguments are evaluated. In your for implementation, the evaluation would be processed like this:
evaluate (< i to)
evaluate expansion result of b1 ...
evaluate (loop (+ i 1)) <- here goes into infinite loop!
evaluate my-when
Item 1-3 can be reverse or undefined order depending on your implementation but the point is nr. 4. If my-when is implemented as a macro, then the macro is the first one to be evaluated.
If you really need to implement with a procedure, then you need to use sort of delaying trick such as thunk. For example:
(define (my-when pred body) (if (pred) (body)))
(my-when (lambda () (< i 10)) (lambda () (display i) (loop (+ i 1))))

Macro to record evaluation steps and intermediate values in Racket?

As an exercise in learning the Racket macro system, I've been implementing a unit testing framework, based on the C++ catch framework. One of the features of that framework is that if I write a check like this:
CHECK(x == y); // (check x y)
When the check is violated the error message will print out the values of x and y, even though the macro used is completely generic, unlike other test frameworks that require you to use macros like CHECK_EQUALS, CHECK_GREATER, etc. This is possible through some hackery involving expression templates and operator overloading.
It occurs to me that in Racket you should be able to do an even better job. In the C++ version the macro can't see inside subexpressions, so if you write something like:
CHECK(f(x, g(y)) == z); // (check (= (f x (g y)) z))
When the check is violated you only find out the values of the left and right hand side of the equal sign, and not the values of x, y, or g(y). In racket I expect it should be possible to recurse into subexpressions and print a tree showing each step of the evaluation.
Problem is I have no idea what the best way to do this is:
I've gotten fairly familiar with syntax-parse, but this seems beyond its abilities.
I read about customizing #%app which almost seems like what I want, but if for example f is a macro, I don't want to print out every evaluation of the expressions that are in the expansion, just the evaluations of the expressions that were visible when the user invoked the check macro. Also not sure if I can use it without defining a language.
I could use syntax-parameterize to hijack the meaning of the basic operators but that won't help with function calls like g(y).
I could use syntax->datum and manually walk the AST, calling eval on subexpressions myself. This seems tricky.
The trace library almost looks like what it does what I want, but you have to give it a list of functions upfront, and it doesn't appear to give you any control over where the output goes (I only want to print anything if the check fails, not if it succeeds, so I need to save the intermediate values to the side as execution proceeds).
What would be the best or at least idiomatic way to implement this?
Here is something to get you started.
#lang racket
(require (for-syntax syntax/parse racket/list))
(begin-for-syntax
(define (expression->subexpressions stx)
(define expansion (local-expand stx 'expression '()))
(syntax-parse expansion
#:datum-literals (#%app quote)
[x:id (list #'x)]
[b:boolean (list #'b)]
[n:number (list #'n)]
; insert other atoms here
[(quote literal) (list #'literal)]
[(#%app e ...)
(cons stx
(append-map expression->subexpressions (syntax->list #'(e ...))))]
; other forms in fully expanded syntax goes here
[else
(raise-syntax-error 'expression->subexpressions
"implement this construct"
stx)])))
(define-syntax (echo-and-eval stx)
(syntax-parse stx
[(_ expr)
#'(begin
(display "] ") (displayln (syntax->datum #'expr))
(displayln expr))]))
(define-syntax (echo-and-eval-subexpressions stx)
(syntax-parse stx
[(_ expr)
(define subs (expression->subexpressions #'expr))
(with-syntax ([(sub ...) subs])
#'(begin
; sub expressions
(echo-and-eval sub)
...
; original expression
(echo-and-eval expr)))]))
(echo-and-eval-subexpressions (+ 1 2 (* 4 5)))
The output:
] (+ 1 2 (* 4 5))
23
] +
#<procedure:+>
] 1
1
] 2
2
] (#%app * '4 '5)
20
] *
#<procedure:*>
] 4
4
] 5
5
] (+ 1 2 (* 4 5))
23
An alternative to printing everything is to add a marker for stuff that should be shown. Here's a rough simple sketch:
#lang racket
(require racket/stxparam)
(define-syntax-parameter ?
(λ(stx) (raise-syntax-error '? "can only be used in a `test' context")))
(define-syntax-rule (test expr)
(let ([log '()])
(define (log! stuff) (set! log (cons stuff log)))
(syntax-parameterize ([? (syntax-rules ()
[(_ E) (let ([r E]) (log! `(E => ,r)) r)])])
(unless expr
(printf "Test failure: ~s\n" 'expr)
(for ([l (in-list (reverse log))])
(for-each display
`(" " ,#(add-between (map ~s l) " ") "\n")))))))
(define x 11)
(define y 22)
(test (equal? (? (* (? x) 2)) (? y)))
(test (equal? (? (* (? x) 3)) (? y)))
which results in this output:
Test failure: (equal? (? (* (? x) 3)) (? y))
x => 11
(* (? x) 3) => 33
y => 22

how to do value assignment issue in lisp

I am learning common lisp and tried to implement a swap value function to swap two variables' value. Why the following does not work?
(defun swap-value (a b)
(setf tmp 0)
(progn
((setf tmp a)
(setf a b)
(setf b tmp))))
Error info:
in: LAMBDA NIL
; ((SETF TMP A) (SETF A B) (SETF B TMP))
;
; caught ERROR:
; illegal function call
; (SB-INT:NAMED-LAMBDA SWAP-VALUE
; (A B)
You can use the ROTATEF macro to swap the values of two places. More generally, ROTATEF rotates the contents of all the places to the left. The contents of the
leftmost place is put into the rightmost place. It can thus be used with more than two places.
dfan is right, this isn't going to swap the two values.
The reason you are getting that error though is that this:
(progn
((setf tmp a)
(setf a b)
(setf b tmp)))
should be this:
(progn
(setf tmp a)
(setf a b)
(setf b tmp))
The first progn has one s-expression in the body, and it's treated
as an application of the function (setf tmp a). In Common Lisp, I
think that only variables or lambda forms can be in the function
position of an application. I could be wrong about the details here,
but I know there are restrictions in CL that aren't in Scheme. That's
why it's an illegal call.
For instance, this is illegal in CL and results in the same error:
CL-USER> ((if (< 1 2) #'+ #'*) 2 3)
; in: LAMBDA NIL
; ((IF (< 1 2) #'+ #'*) 2 3)
;
; caught ERROR:
; illegal function call
;
; compilation unit finished
; caught 1 ERROR condition
You COULD write a swap as a macro (WARNING: I'm a Lisp noob, this
might be a terrible reason for a macro and a poorly written one!)
(defmacro swap (a b)
(let ((tmp (gensym)))
`(progn
(setf ,tmp ,a)
(setf ,a ,b)
(setf ,b ,tmp))))
Nope! Don't do this. Use rotatef as Terje Norderhaug points out.
A function (rather than macro) swapping two special variables can take the variable symbols as arguments. That is, you quote the symbols in the call. Below is an implementation of such a swap function:
(defvar *a* 1)
(defvar *b* 2)
(defun swap-values (sym1 sym2)
(let ((tmp (symbol-value sym1)))
(values
(set sym1 (symbol-value sym2))
(set sym2 tmp))))
? (swap-values '*a* '*b*)
2
1
? *a*
2
Note the use of defvar to define global/special variables and the per convention use of earmuffs (the stars) in their names. The symbol-value function provides the value of a symbol, while set assigns a value to the symbol resulting from evaluating its first argument. The values is there to make the function return both values from the two set statements.
You can not use setf to build a lexical variable tmp. You can use let, as follow:
(defun swap-value (a b)
(let ((tmp 0))
(setf tmp a)
(setf a b)
(setf b tmp))
(values a b))
which will do you hope.
Complimentary to other answers, the OP's targeted problem - the (multiple) value assignment issue - can be solved by parallel assignment using psetf:
(let ((a 21)
(b 42))
(psetf a b
b a)
(print (list a b)))
;; (42 21)