Scheme macros with 2 params - macros

Can I define macro that will get one param from left and one from right part of macro? I want to write some kind of this in my programs:
(test = 10)
to define new variables
I tried to write that macro:
(define-syntax =
(syntax-rules ()
((a _ b)
(define a b))))
But I've got error "bad syntax in: ="

Since the form is determined by the first element you'd have problems with test not being bound.
The right way is this:
(= test 10)
You write the macro like this:
(define-syntax =
(syntax-rules ()
((_ a b) (define a b))))
There you go. Without horrible infix syntax.

Related

Macro-defining macro in Racket?

In Common Lisp it is relatively easy to create a macro-defining macro. For example, the following macro
(defmacro abbrev (short long)
`(defmacro ,short (&rest args)
`(,',long ,#args)))
is a macro-defining macro, because it expands to another macro.
If we now put
(abbrev def defun)
in our program, we can write def instead of defun whenever we define a new function.
Of course, abbrev can be used for other things, too. For example, after
(abbrev /. lambda)
we can write (/. (x) (+ x 1)) instead of (lambda (x) (+ x 1)). Nice. (For detailed explanation of abbrev, see http://dunsmor.com/lisp/onlisp/onlisp_20.html)
Now, my questions are:
Can I write the macro-defining macros in Racket?
If I can, how to do that? (for example, how to write something similar to
abbrev macro in Racket?)
According to this part of the Racket Guide:
(define-syntax-rule (abbrev short long)
(define-syntax-rule (short body (... ...))
(long body (... ...))))
Quoting the above link:
The only non-obvious part of its definition is the (... ...), which
“quotes” ... so that it takes its usual role in the generated macro,
instead of the generating macro.
Now
(abbrev def define)
(abbrev /. lambda)
(def f (/. (x) (+ x 1)))
(f 3)
yields
4
FWIW, it works on Guile as well, so it's no Racket-specific thing.
ad 1. Yes.
ad 2. Your example can most easily be written
#lang racket
(define-syntax (abbrev stx)
(syntax-case stx ()
[(_ short long)
#'(define-syntax short (make-rename-transformer #'long))]))
(abbrev def define)
(def x 42)
x
The example above evaluates to 42.
I find that renaming can be done simply with define or let statements:
(define =? =)
(define lr list-ref)
or:
(let ((=? =)
(lr list-ref))
(println (lr '(1 2 3) 2))
(println (=? 1 2))
(println (=? 1 1)))
Output:
3
#f
#t
There seem to be no need for any macro for this purpose.

Creating a function to return a core expression using macros

I've been working on some code using R5RS for an assignment to expand certain expressions into core forms of the expression using macros. These are put through a provided eval/apply loop later
(define expand (lambda (exp)
(letrec-syntax
((let (syntax-rules ()
((_ ((var init) ...) body ...)
(`((lambda (var ...) body ...) init ...))))) )
(exp)) ; sequence to expand
))
(expand (let ((x 2) (y 1)) (+ x y)) )
When I run the code like this I get back ;The object 3 is not applicable. but so it looks like it's actually evaluating exp, but I need to get back a uh...string representation.
If I embed the expression I want expanded into the letrec-syntax body I get back what I actually want. Like so:
(define expand (lambda (exp)
(letrec-syntax
((let (syntax-rules ()
((_ ((var init) ...) body ...)
(`((lambda (var ...) body ...) init ...))))) )
(let ((x 2) (y 1)) (+ x y))) ; sequence to expand
))
I get back ...
;The object ((lambda (x y) (+ x y)) 2 1) is not applicable Which looks like what I want to send back to be interpreted.
So my question is how can I rewrite this to take any exp given to expand like in the first example, but return its expanded form like in the second example?
I think the problem has something to do with exp defined by lambda being in the wrong scope in regards to letrec-syntax. I'm very new to Scheme, and I feel like I'm missing a simple solution here. My best leads so far involve using syntax-case somehow or something about hygienics, but I feel like I've been chasing my tail trying to research those topics so far and I'm not sure they're the right direction.
Thanks for any assistance. :)
This works:
(define-syntax expand
(syntax-rules (let)
((_ (let ((var init) ...) body ...))
'((lambda (var ...) body ...) init ...))))
then
> (expand (let ((x 2) (y 1)) (+ x y)))
((lambda (x y) (+ x y)) 2 1)

When should I use syntax/loc instead of #' (aka syntax)?

A new syntax object can be constructed by both syntax/loc and syntax (also written #').
When should I use syntax/loc?
Use #' (i.e. syntax) when you are not constructing a new syntax object, as when you're just referencing a pattern variable bound with syntax-case or with-syntax.
Use #' for temporary syntax objects as in (syntax->list #'(id ...)).
Use #' for syntax objects representing forms that you know won't have syntax errors in them, or where syntax errors in them are the fault of your macro implementation, not the use of your macro.
Use syntax/loc when you construct expressions that potentially can contain syntax-errors due to an incorrect usage of your macro.
Let's consider a concrete example:
The form display-let should work exactly like normal let, except that it displays the values of the bindings before it evaluates the body.
Here is a first implementation:
(define-syntax (display-let-1 stx)
(syntax-case stx ()
[(_ ([id expr] ...) body ...)
#'((lambda (id ...)
(displayln (format "~a is bound to ~a" 'id id)) ...
body ...)
expr ...)]))
Here is an example of a correct use of the macro:
> (display-let-1 ([x 1] [y 2]) (+ x y))
x is bound to 1
y is bound to 2
3
Now let us see what happens when the macro is used incorrectly:
> (display-let-1 ())
lambda: bad syntax in: (lambda ())
This usage is incorrect, since a use of let must always have a non-empty body. Besides printing the error message, DrRacket colors this code red:
(lambda (id ...)
(displayln (format "~a is bound to ~a" 'id id)) ...
body ...)
Although it is correct that the lambda expression constructed by the macro is incorrect, (lambda ()) is not legal, it is not due to an error in the macro, but due to an incorrect use of the macro.
To redirect the blame surround the constructed lambda expression with syntax/loc and use the first argument of syntax/loc as place to color red.
(define-syntax (display-let-2 stx)
(syntax-case stx ()
[(display-let ([id expr] ...) body ...)
#`(#,(syntax/loc stx (lambda (id ...) body ...)) expr ...)]))
> (display-let-2 ())
display-let-2: bad syntax in: (display-let-2 ())
This time around the (display-let-2 ()) entered in the repl is colored red, and the error message mentioned display-let-2 instead of lambda.

While Loop Macro in DrRacket

I am trying to create a macro for while loop in DrRacket. Here is what I wrote:
(require mzlib/defmacro)
(define-macro my-while
(lambda (condition body)
(list 'local (list (list 'define (list 'while-loop)
(list 'if condition
(list body (list 'while-loop))
'(void))))
'(while-loop))))
(define x 0)
(my-while (< x 10)
(begin
(display x)
(newline)
(set! x (+ x 1))))
The output of this program is:
0
1
2
3
4
5
6
7
8
9
error: procedure application: expected procedure, given: #<void>; arguments were: #<void>
Can someone help me with this? Why wouldn't this macro just terminate and return void. It seems that when the condition is not true, the system tries to apply the void as an argument to some procedure.
Ouch:
Using this style of while loop encourages excessive use of imperative programming.
Using define-macro creates unhygienic macros, which is a nightmare in Scheme.
While I don't encourage writing an imperative-style loop macro, for your reference, here's a non-define-macro version of the same macro:
(define-syntax-rule (my-while condition body ...)
(let loop ()
(when condition
body ...
(loop))))
It uses syntax-rules, which creates hygienic macros, and is much, much easier to read than what you have.
Now, for the actual answer for your question, first, let's write your original macro out in a more readable way:
(define-macro my-while
(lambda (condition body)
`(local ((define (while-loop)
(if ,condition
(,body (while-loop))
(void))))
(while-loop))))
Once you write it out this way, you can see where the real problem is: in the (,body (while-loop)) line, which should instead have been (begin ,body (while-loop)).
Why use a macro when a plain old function will do?
;; fun-while : (-> Boolean) (-> Any) -> Void
(define (fun-while condition body)
(when (condition)
(body)
(fun-while condition body))
Of course, this requires you to pass in repeatable actions that can be called (this is why condition and body are surrounded with parens in the body of fun-while), so you do need a macro if you want prettier syntax. But once you have a function that has the desired behavior, putting some sugar on top is trivial for this case:
(define-syntax-rule (my-while condition body ...)
(fun-while (lambda () condition)
(lambda () body ...)))
Now, as has been said, this encourages imperative style, which is frowned upon. Instead of mutation, try making the state explicit instead:
;; pure-while : forall State.
;; (State -> Boolean) ; the "condition" that inspects the state
;; (State -> State) ; the "body" that moves from one state to the next
;; -> ; curried
;; State ; the current state
;; -> State ; produces the ending state
(define ((pure-while condition make-next) current-state)
(if (condition current-state)
(pure-while condition make-next (make-next current-state))
current-state))
You'll notice that the first two arguments are now functions from State to something, and the result of applying to 2 arguments is also a function from State -> State. This is a recurring pattern that, as a Haskeller, I'd call the "State Monad". Discussion of putting sugar on top of this concept is a little beyond the scope of this conversation, though, so I'll just stop there.
Another version of while uses a do loop:
(define-syntax while
(syntax-rules ()
((while pred? stmt ...)
(do () ((not pred?))
stmt ...))))
Because it's been a while:
a while macro for Racket 6.0
#lang racket
(define-syntax while
(syntax-rules ()
((_ pred? stmt ...)
(do () ((not pred?))
stmt ...))))

set! global from Scheme macro?

I am trying to write a wrapper for define, that stores the values passed to it. I've been approaching it in baby steps (being new to Lisp in general, and even newer to Scheme) but have run into a wall.
In Racket, I'm starting with:
> (require (lib "defmacro.ss"))
> (define-macro (mydefine thing definition)
`(define ,thing ,definition))
> (mydefine a 9)
> a
9
Okay, that works. Time to do something in the macro, prior to returning the s-exprs:
> (define-macro (mydefine thing definition)
(display "This works")
`(define ,thing ,definition))
> (mydefine a "bob")
This works
> a
"bob"
Nice. But I can't for the life of me get it to set a global variable instead of displaying something:
> (define *myglobal* null)
> (define-macro (mydefine thing definition)
(set! *myglobal* "This does not")
`(define ,thing ,definition))
> (mydefine a ":-(")
set!: cannot set identifier before its definition: *myglobal*
Any suggestions on how to accomplish this would be greatly appreciated.
I suspect that I'm trying to swim against the current here, either by fiddling with globals from a macro in Scheme, or by using define-macro instead of learning the Scheme-specific syntax for macro creation.
You're running against Racket's phase separation -- which means that each phase (the runtime and the compile-time) operate in different worlds. As Vijay notes, one way to solve this is to do what you want at runtime, but that will probably not be what you need in the long run. The thing is that trying these things usually means that you will want to store some syntactic information at the compile-time level. For example, say that you want to store the names of all of your defined names, to be used in a second macro that will print them all out. You would do this as follows (I'm using sane macros here, define-macro is a legacy hack that shouldn't be used for real work, you can look these things up in the guide, and then in the reference):
#lang racket
(define-for-syntax defined-names '())
(define-syntax (mydefine stx)
(syntax-case stx ()
[(_ name value)
(identifier? #'name)
(begin (set! defined-names (cons #'name defined-names))
#'(define name value))]
;; provide the same syntactic sugar that `define' does
[(_ (name . args) . body)
#'(mydefine name (lambda args . body))]))
Note that defined-names is defined at the syntax level, which means that normal runtime code cannot refer to it. In fact, you can have it bound to a different value at the runtime level, since the two bindings are distinct. Now that that's done, you can write the macro that uses it -- even though defined-names is inaccessible at the runtime, it is a plain binding at the syntax level, so:
(define-syntax (show-definitions stx)
(syntax-case stx ()
[(_) (with-syntax ([(name ...) (reverse defined-names)])
#'(begin (printf "The global values are:\n")
(for ([sym (in-list '(name ...))]
[val (in-list (list name ...))])
(printf " ~s = ~s\n" sym val))))]))
The statement (set! *myglobal* "This does not") is executed in the transformer environment, not the normal environment. So it's not able to find *myglobal. We need to get both the expressions executed in the environment where *myglobal* is defined.
Here is one solution:
(define *defined-values* null)
(define-macro (mydefine thing definition)
`(begin
(set! *defined-values* (cons ,definition *defined-values*))
(define ,thing ,`(car *defined-values*))))
> (mydefine a 10)
> (mydefine b (+ 20 30))
> a
10
> b
50
> *defined-values*
(50 10)
> (define i 10)
> (mydefine a (begin (set! i (add1 i)) i)) ;; makes sure that `definition`
;; is not evaluated twice.
> a
11
If the Scheme implementation does not provide define-macro but has define-syntax, mydefine could be defined as:
(define-syntax mydefine
(syntax-rules ()
((_ thing definition)
(begin
(set! *defined-values* (cons definition *defined-values*))
(define thing (car *defined-values*))))))