Racket macro for expanding code - macros

I want to be able to write:
(nota E2 82)
instead of:
(define E2
(network ()
[sunet <= sine-wave 82]
[out = (+ sunet)]))
I know I can do this using macros and tried to write this:
(define-syntax (nota stx)
(syntax-case stx ()
[(nota x) #'(network ()
[sunet <= sine-wave x]
[out = (+ sunet)])]))
But I get this error:
nota: bad syntax in: (nota E2 82)

The simplest solution would be
(define-syntax-rule (nota x y)
(define x
(network ()
[sunet <= sine-wave y]
[out = (+ sunet)])))

Okay, that's just awful. You really shouldn't need to write this macro; there should be a form that supplies fixed inputs to a network.
In fact, there is. But... it's not documented, and it's not well named. It's currently called fixed-inputs, but I'm going to rename it as network-const, and document it.
Thanks for prompting me on this!
John

Related

Two questions about Racket macro

About hygienic macro
I don't fully understand how hygienic macro work. Here is two example.
first one is:
#lang racket
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(let ([display 1])
(g 3))
this works fine but this one:
#lang racket
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(define display 1)
(g 3)
will raise an exception. How to explain the difference between the two case?
How to define a macro like this
I want to define a macro to allow anonymous recursive function in racket.
This one won't work because recur is not defined in the module:
#lang racket
(define Z
(λ(recur)
((λ(x) (recur (λ(y) (x x) y)))
(λ(x) (recur (λ(y) (x x) y))))))
(define-syntax-rule (R proc)
(Z (λ(recur) proc)))
((R (λ(n)
(if [= n 1]
1
(* n (recur (- n 1)))))) 3)
How to achieve this?
To answer your first question, the thing your forgetting here is that when you do a module level define like that, that definition is bound for the whole module. So, you could, theoretically write your second code block like this:
#lang racket
(let ([display 1])
(define-syntax (g stx)
(syntax-case stx ()
([_ arg]
#'(display arg))))
(g 3))
And now it makes sense why you get an error, because the display in your macro is bound to 1, which is not a function.
Long story short, think of hygiene just as lexical scope. Whatever display is bound to when you define your macro is what it will be. (This is opposed to macros in other languages, where whatever display is bound to when you call (or really expand) the macro, is what it will be.
Now, to answer your second question, I apologize, but am unclear what you are trying to ask here. If you could clean it up a bit then I can fill in this part of the answer.
So you want to break hygene? You need to get recur to have the lexical context of the original form such that recur will be seen as the same identifier. You can do this with datum->syntax and the result might look something like this:
(define-syntax (recur-λ stx)
(syntax-case stx ()
[(_ args body ...)
(with-syntax ([recur-stx (datum->syntax stx 'recur)])
#'(Z (λ (recur-stx)
(λ args body ...))))]))
Now as long as your args or the nesting in body introduces recur it will work:
; multiple argument recursion
(define Z
(λ (f)
((λ (g) (g g))
(λ (g)
(f (λ args (apply (g g) args)))))))
; ackerman
((recur-λ (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (recur (- m 1) 1))
(else (recur (- m 1) (recur m (- n 1))))))
3
6)
; ==> 509
It won't work if you make recur an argument:
((recur-λ (recur) (recur 1)) 1)
; ==> error: recur not a procedure
And of course if you make a nested binding:
((recur-λ (a)
(define recur a)
(recur 1))
1)
; ==> error: recur not a procedure
And of course you can step through the macroexpander and it will show you that it does something like this:
(expand-once
#'(recur-λ (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (recur (- m 1) 1))
(else (recur (- m 1) (recur m (- n 1)))))))
; ==>
; #'(Z
; (λ (recur)
; (λ (m n)
; (cond
; ((= m 0) (+ n 1))
; ((= n 0) (recur (- m 1) 1))
; (else (recur (- m 1) (recur m (- n 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

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)

for/list vs custom for/bytes in Racket

I'm playing around with Racket and missed a byte-string comprehension. When I found for/fold/derived with examples in the documentation, I decided to roll my own byte-string comprehension macro, as any beginner would:
(define-syntax (for/bytes stx)
(syntax-case stx ()
((_ clauses . defs+exprs)
(with-syntax ((original stx))
#'(let-values
(((bstr i max-length)
(for/fold/derived original ((bstr (make-bytes 16)) (c 0) (ln-incr 32)) clauses
(define el (let () . defs+exprs))
(let-values (((new-bstr new-ln-incr)
(if (eq? c (bytes-length bstr))
(values (bytes-append bstr (make-bytes ln-incr)) (* ln-incr 2))
(values bstr ln-incr))))
(bytes-set! new-bstr c el)
(values new-bstr (+ c 1) new-ln-incr)))))
(subbytes bstr 0 i))))))
I've got a few related questions:
Is this the Racket way anyhow?
Is the macro ok? Basically I combined the examples from the for/fold/derived documentation with a macro-expaned for/vector
Are there any obvious performance optimizations?
Sadly, it's not really faster than (list->bytes (for/list ... This micro-benchmark:
(define size 50000)
(define (custom-byte-test) (for/bytes ((i (in-range size))) (modulo i 256)))
(define (standard-list-test) (list->bytes (for/list ((i (in-range size))) (modulo i 256))))
(profile-thunk custom-byte-test #:repeat 1000)
(profile-thunk standard-list-test #:repeat 1000)
gives 3212ms vs 3690ms. For sizes much smaller than 50000 my for/bytes loses, for sizes bigger than that it wins.
My answers:
Is this the Racket way anyhow?
Yes.
Is the macro ok? Basically I combined the examples from the for/fold/derived documentation with a macro-expand for/vector
Yes, I think it looks good.
Are there any obvious performance optimizations? Sadly, it's not really faster than (list->bytes (for/list ...
I'm not aware of how to do it faster. The "win" here is that the complexity of buffer resizing is hidden from users of for/bytes.
I sped your code up a little.
1) The bytes-length calculation in the inner loop is unneeded since you already know the current length. I replaced your ln-incr with a bstr-len that represents both the current length and the amount to increase the length.
This gave ~15% improvement.
2) Since you already do length checking, you can safely use unsafe-bytes-set!, which speeds things up another ~10%.
On my machine, custom-byte-test is now ~1200ms vs ~1750ms for standard-list-test.
#lang racket
(require racket/unsafe/ops profile)
(define-syntax (for/bytes stx)
(syntax-case stx ()
[(_ clauses . defs+exprs)
(with-syntax ([original stx])
#'(let ([init-bstr-len 32])
(let-values
([(bstr i max-length)
(for/fold/derived
original
([bstr (make-bytes init-bstr-len)]
[c 0]
[bstr-len init-bstr-len]) ; <-- use as curr len + extend len
clauses
(define el (let () . defs+exprs))
(let-values
([(new-bstr new-bstr-len)
(if (= c bstr-len) ; <-- remove len calculation
(values
(bytes-append bstr (make-bytes bstr-len))
(* bstr-len 2))
(values bstr bstr-len))])
(unsafe-bytes-set! new-bstr c el) ; <-- unsafe op
(values new-bstr (add1 c) new-bstr-len)))])
(subbytes bstr 0 i))))]))
(define size 50000)
(define (custom-byte-test)
(for/bytes ([i (in-range size)]) (modulo i 256)))
(define (standard-list-test)
(list->bytes (for/list ([i (in-range size)]) (modulo i 256))))
(profile-thunk custom-byte-test #:repeat 1000)
(profile-thunk standard-list-test #:repeat 1000)

define-match-expander

about the define-match-expansion, there are rare materials and example codes to illustrate the concepts. I am having a hard time to "decode" what the documentation says:
(define-match-expander id proc-expr)
(define-match-expander id proc-expr proc-expr)
Binds id to a match expander.
The first proc-expr subexpression must
evaluate to a transformer that
produces a pat for match. Whenever id
appears as the beginning of a pattern,
this transformer is given, at
expansion time, a syntax object
corresponding to the entire pattern
(including id). The pattern is the
replaced with the result of the
transformer.
A transformer produced by a second
proc-expr subexpression is used when
id is used in an expression context.
Using the second proc-expr, id can be
given meaning both inside and outside
patterns.
Can anyone give some example codes to illustrate the two usages of the define-match-expander here?
The idea behind match-expander is that you can extend the 'match' form to handle new pattern forms of your own design.
So, here's a (somewhat pointless) example that defines an "aba" match form that matches patterns of one thing followed by another thing followed by the first thing again (hence, "aba"):
#lang racket
(define-match-expander aba
(lambda (stx)
(syntax-case stx ()
[(_ a b) #'(list a b a)])))
(match '(3 4 3)
[(aba x y) (printf "x = ~a, y = ~a" x y)])
The second form allows you to add a separate expansion to be used outside of match patterns, like this:
#lang racket
(define-match-expander aba
(lambda (stx)
(syntax-case stx ()
[(_ a b) #'(list a b a)]))
(lambda (stx)
#'(error "please don't use aba outside of patterns.")))
(match '(3 4 3)
[(aba x y) (printf "x = ~a, y = ~a\n" x y)])
(aba x y)
Caveat: whuffo the extra pair of parens around the pattern? Not sure, sorry.
This is a really old question, but I'd like to add the example using "syntax-rules" for the same "aba" pattern:
(define-match-expander aba
(syntax-rules ()
[(aba a b) (list a b a)]))
(match '(3 4 3)
[(aba x y) (printf "x = ~a, y = ~a" x y)])
Left-hand side (aba a b) is the thing going in the match, the right-hand side (list a b a) is the substitution.
(match '(3 4 3)
[(aba x y) (printf "x = ~a, y = ~a" x y)])
is replaced by
(match '(3 4 3)
[(list x y x) (printf "x = ~a, y = ~a" x y)])
The nice part is that the new matcher works for ALL "match-whatever" functions, like:
(match-define (aba x y) (list 1 2 1))
(printf "x = ~a, y = ~a" x y