I need to define a syntax for a fancy-sublist procedure that works like this
> (fancy-sublist 1 2 -> 3 4 5 <- 6 7)
(3 4 5)
I tried to implement it by defining a new syntax
(define-syntax fancy-sublist
(syntax-rules (-> <-)
((_ x xs ... -> dis dis1 ... <- y ys ...)
(keep only the elements in the middle))))
But it seems I cannot put an ellipsis after another.
Is it possible to use define-syntax to do what I want?
Use the syntax/parse library instead of syntax-rules; it’s more capable in every way, and it produces considerably better error messages even when both can technically get the job done. I consider syntax-rules a legacy feature from Scheme; syntax-parse should really be the default choice in modern Racket. It copes with your example perfectly fine:
#lang racket
(require syntax/parse/define)
(define-syntax (<- stx)
(raise-syntax-error #f "cannot be used as an expression" stx))
(define-syntax-parser fancy-sublist
#:literals [<- ->]
[(_ x xs ... -> dis dis1 ... <- y ys ...)
#'(list dis dis1 ...)])
> (fancy-sublist 1 2 -> 3 4 5 <- 6 7)
'(3 4 5)
Related
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
For example,
(require racket/generator)
(define f add1)
(define init 0)
(in-producer (generator () (let loop ([x init]) (yield x) (loop (f x)))))
Is there any better way to do this? I don't quite like generators since they have hidden states.
Streams
Using streams is probably the easiest:
(require racket/stream)
;; X [X -> X] -> [Streamof X]
(define (repeated-fn-stream init f)
(stream-cons init (repeated-fn-stream (f init) f)))
(repeated-fn-stream 0 add1)
Sequences
Alternatively, using sequences and make-do-sequence:
(require racket/sequence)
;; X [X -> X] -> [Sequenceof X]
(define (repeated-fn-sequence init f)
;; A "Pos" is an X that's the result of applying f repeatedly to init
(define (pos->element pos) pos)
(define (next-pos pos) (f pos))
(define init-pos init)
(make-do-sequence
(λ ()
(values pos->element
next-pos
init-pos
#false
#false
#false))))
(repeated-fn-sequence 0 add1)
If you wanted to use sequences, and you wanted to use define-sequence-syntax to make for loops specialize it:
(this is completely unnecessary for "pure" functionality, but it may have different performance characteristics)
(require (for-syntax syntax/parse))
(define-sequence-syntax in-repeated-fn-sequence
(λ () #'repeated-fn-sequence) ; when used as a normal expression
(syntax-parser ; when used *directly* as a for-loop clause
[[(x) (_ init-expr f-expr)]
#'[(x) (:do-in
([(init) init-expr] [(f) f-expr])
#true
([x init])
#true
()
#true
#true
[(f x)])]]))
(for/list ([x (in-repeated-fn-sequence 0 add1)]
[i (in-range 10)])
x)
When using define-sequence-syntax, you should make sure that for everything there is a "single point of truth". Because of that you often see this pattern:
(define-sequence-syntax in-___
(λ () #'in-___/proc) ; when used as a normal expression
(syntax-parser
....everything that defines the actual functionality....))
;; This is completely determined by the sequence-syntax above,
;; that way there is NO duplicated functionality and NO chance for
;; it to get "out of sync".
(define (in-___/proc parameter ...)
(for/stream ([elem (in-___ parameter ...)])
elem))
What that means for this is that once you decide you want to use define-sequence-syntax, you should define the repeated-fn-sequence function in terms of it:
(define (repeated-fn-sequence init f)
(for/stream ([elem (in-repeated-fn-sequence init f)])
elem))
That way if the in-repeated-fn-sequence needs to be changed to fix a bug or switch representations, the function version changes with it automatically.
The best function for this job is an unfold… but unfortunately, Racket does not provide a built-in sequence-unfold or stream-unfold operation. However, there is a stream-unfold operation in the srfi/41 library, which will meet your needs. You can see this in action with the following program:
#lang racket
(require (only-in srfi/41 stream-unfold))
(define nats (stream-unfold identity (const #t) add1 0))
(for/list ([i (in-range 20)] [n nats]) n)
This produces the following output:
'(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
If you don’t want to use srfi/41, you can write stream-unfold yourself in terms of the racket/stream API without too much difficulty, and without any statefulness:
(define (stream-unfold mapper pred? gen base)
(let loop ([base base])
(if (pred? base)
(stream-cons (mapper base) (loop (gen base)))
empty-stream)))
From https://www.gnu.org/software/guile/manual/html_node/Syntax-Rules.html#Syntax-Rules I got the following macro example:
(define-syntax simple-let
(syntax-rules ()
((_ (head ... ((x . y) val) . tail)
body1 body2 ...)
(syntax-error
"expected an identifier but got"
(x . y)))
((_ ((name val) ...) body1 body2 ...)
((lambda (name ...) body1 body2 ...)
val ...))))
I am trying to understand how this macro works. So I annotated it a little:
;; EXAMPLE 7
;; Reporting errors at macro-expansion time (read time, compile time).
(define-syntax simple-let
(syntax-rules ()
[(simple-let (head ... ((x . y) val) . tail)
; (1) head ... can also be zero times?
; (2) what is `. tail` matching?
; (3) can I not use two ellipsis on the
; same level instead of `. tail`?
body1
body2 ...)
(syntax-error "expected an identifier but got"
(x . y))]
;; if there ((a . b) val) is not matched
[(simple-let ((name val) ...)
body1
body2 ...)
((lambda (name ...)
body1
body2 ...)
val ...)]))
The only part I do not really understand in terms of how it works is the first match expression:
(simple-let (head ... ((x . y) val) . tail)
So I tried a few examples:
;; simply working
(simple-let ([a 3])
(+ a 4))
;; caught
(simple-let ([(a . b) 3]) ; Q: What is `. tail` matching in this one?
(+ a 4))
(simple-let ([a 3] [(b . c) 3]) ; Q: What is `. tail` matching in this one?
(+ a b))
;; not caught
(simple-let ([a 3] [(b . c) 3] [d 4]) ; Q: Why is `. tail` not matching `[d 4]`?
(+ a b))
I have difficulties understanding what part is . tail matching and why. I tried using ... instead of . and put it behind tail, in order to catch the example where the syntax error is not caught, because it does not go into the first match case, but it does not work and tells me that it is a bad usage of ellipsis. My guess is, that one cannot have two ellipsis in the same nesting level, because it would be hard to know which ellipsis matches what. Kind of like regular expressions become computationally expensive in some cases.
So what does . tail match in the examples and why is that one example not caught?
usually tail matches the rest of the list e.g.
for '(1 2 3 4) matching with the pattern (1 . x), x matches '(2 3 4).
The result is confusing so one need to go to the sources to see the implementaion (see ice-9/psyntax.scm)
There one can see that the ellipsis is translated to (each+ x y z) with z in this case is tail and is matching the last cdr which in all your cases is '().
In the example ... is gready and . tail is not. If you are dissatisfied with how this behavior is documented or want to change the implementation you may ask on the guile-devel mailing list: guile-devel#gnu.org
Guile has also syntax-parse as a downloadable lib (search for guile-syntax-parse) which is a port of racket's syntax-parse as of a couple of years ago (see racket's documentation if you are curious) I coded your example with syntax-parse and that seamed to execute as you expected.
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
I have a Scheme macro and a long list, and I'd like to map the macro across the list, just as if it were a function. How can I do that using R5RS?
The macro accepts several arguments:
(mac a b c d)
The list has
(define my-list ((a1 b1 c1 d1)
(a2 b2 c2 d2)
...
(an bn cn dn)))
And I'd like to have this:
(begin
(mac a1 b1 c1 d2)
(mac a2 b2 c2 d2)
...
(mac an bn cn dn))
(By the way, as you can see I'd like to splice the list of arguments too)
Expanding on z5h's answer of using eval, the methods below show how a map-macro macro can be written if interaction-environment in implemented in the version of R5RS in use:
(define test-list '((1 2 3 4)
(5 6 7 8)))
;Or if your version of scheme implments interaction-environment then:
(define-syntax trade
(syntax-rules ()
((_ a b c d) (display (list b a d c)))))
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;Careful this is not really mapping. More like combined map and apply.
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
(define-syntax map-macro
(syntax-rules ()
((_ mac ls) (let ((mac-list (map (lambda (lst) (cons 'trade lst)) ls)))
(eval
`(begin
,#mac-list)
(interaction-environment))))
))
(map-macro trade test-list)
;outputs: (2 1 4 3)(6 5 8 7)
So that last map-macro call evaluates the following:
What ends up getting evaluated from (map-macro trade test-list) is:
(begin
(trade 1 2 3 4)
(trade 5 6 7 8))
Which is not quite a map, but I believe it does answers your question.
Syntactic extensions are expanded into
core forms at the start of evaluation
(before compilation or interpretation)
by a syntax expander. -Dybvig, "The
Scheme Programming Language:
A macro operates on syntax. This happens before compilation or execution. It gives you another way of writing the same code.
A function operates on variables and values (which might be lists, atoms, numbers, etc) who's value is known when the function is invoked.
So mapping a macro doesn't make sense. You're asking to invoke something (macro expansion) that already happened long ago.
If you need something to write code for you and evaluate it at runtime, then might be one of those cases where you need eval.
Would something like
(map (lambda (l) (mac (car l) (caar l) (caaar l) (caaaar l))) mylist)
work?