I've never used Racket's macro system before so forgive my ignorance. I'm trying to dynamically define rules in Racket's Datalog system, basically like this:
(datalog rules (! (:- c a b)))
If I put something like this into the code directly, all is well. However, I want to dynamically generate these rules. With regular functions I would just do something like this:
(datalog rules (! (apply :- conclusion premises)))
But datalog, ! and :- are all macros, making this impossible.
My solution was to write this macro:
(define-syntax (make-rule stx)
(syntax-case stx ()
((_ premises conclusion)
#`(datalog rules (! (:- ,conclusion ,#(map (lambda (x) `,x) premises)))))))
Which is then called like this:
(make-rule '(a b) 'c)
However while this does run, querying the Datalog database renders nothing when both a and b are true.
I tried double quoting the syntax object so I could see just what was getting output, and it's this:
'(datalog rules (! (:- c a b)))
So... Exactly what should and does work if I just type it directly in my code! What is going on here? Is this some sort of hygenic macro thing? I really have no idea.
Thanks!
Edit: Here is a complete runnable example of the problem.
#lang racket
(require datalog)
(define rules (make-theory))
(define-syntax (make-rule stx)
(syntax-case stx ()
((_ premises conclusion)
#`(datalog rules (! (:- ,conclusion ,#(map (lambda (x) `,x) premises)))))))
(make-rule '(a b) 'c)
(datalog rules (? c)) ;;Does not work.
(datalog rules (! (:- c a b)))
(datalog rules (! a) (! b))
(datalog rules (? c)) ;;Works.
OK I think I have it for you. It was not a hygiene problem.
#lang racket
(require datalog)
(define rules (make-theory))
(define-syntax (make-rule stx)
(syntax-case stx ()
((_ (ps ...) c)
#'(datalog rules (! (:- c ps ...))))))
(datalog rules (! a) (! b))
(make-rule (a b) c)
(datalog rules (? c))
The problem is with the quoting/unquoting. Here I just modified the template to accept the form you're giving it. Again I'm not really understanding the datalog language but this gives the same output as what you said "works" in your example.
Related
In a custom Racket language, I would like to change the behavior of the core form if as well as other forms that expand to it (such as and and cond).
Naturally, I could redefine each of these forms but this seems rather redundant. For instance, here is an example where the modified if expects each of its arguments to be wrapped in a list. The macro and is here redefined explicitly.
;; my-lang.rkt
#lang racket/base
(require (for-syntax racket/base))
(provide #%module-begin #%datum #%app
list
(rename-out [car-if if] [car-and and]))
(define-syntax (car-if stx)
(syntax-case stx ()
[(_ c t f) #'(if (car c) t f)]))
(define-syntax (car-and stx) ; this seems redundant
(syntax-case stx ()
[(_) #'#t]
[(_ x) #'x]
[(_ x xs ...) #'(car-if x (car-and xs ...) x)]))
#lang s-exp "my-lang.rkt"
(if (list #f) (list 2) (list 3)) ; => (3)
(and (list #f) (list 2)) ; => (#f)
Is there an easier way to redefine these forms by injecting my new definition of if into the existing definitions provided by racket/base?
The answer is no.
Let's consider the form and. It is defined as a macro (somewhere).
It looks something like:
#lang mumble
(define-syntax (and stx)
(syntax-case stx ()
[(_and) #'#t]
[(_and e) #'e]
[(_and e1 e2) #'(let ([t e1]) (if t e2 #f))]
[(_and e1 e2 e ...) #'(let ([t e1]) (if t (and e2 e ...)))]
[_ (raise-syntax-error 'and "bad syntax" stx)]))
Since the Racket macro system is "referentially transparent" the
identifiers are bound using standard lexical scope rules. That is
the if in the expansion is bound to the if in the module where
the macro is defined. The point is that the macro writer doesn't
need to fear any users redefining any identifiers used in the expansion.
The only way to change the behaviour of the and macro above is to
change the if used. So only if you have access to the definition
of "mumble", you can change the if used. In the case of the standard
Racket and no user can change the definitions.
In short, the answer is "no" due to the design of the macro system.
I need to implement my_let* using defmacro which works similarly to let*, but while let* is expanded to a series of nested let calls (behind the scenes), my_let* needs to be expanded to a single let call, and use the define statement to define the arguments i get.
an example of using my_let*:
(my_let* ((a 2)
(b 3)
(c (+ a b)))
(+ a b c))
and the return value of this code should be 10. just as if it was use let*.
the code above will be expanded in my_let* to the following:
(let ()
(define a 2)
(define b 3)
(define c (+ a b))
(+ a b c))
I'm new to using macro, though i successfully written some macros, this one got me lost.
Thank you in advance.
Use syntax-parse. At the least don't even consider using defmacro in Racket.
#lang racket
(require (for-syntax syntax/parse))
(define-syntax (my-let* stx)
(syntax-parse stx
[(_my-let* ([name:id e:expr] ...) body ...)
#'(let ()
(define name e) ...
body ...)]))
The name:id means that name must be an identifier and e:expr means
that e must an expression. These simple annotations help syntax-parse
to give you better error messages.
Example:
(my-let* ((4 2)
(b 3)
(c (+ a b)))
(+ a b c))
Here the DrRacket will color the 4 read and give the message:
my-let*: expected identifier in: 4
The Scheme way is using syntax-rules
(define-syntax my-let*
(syntax-rules ()
((_ ((binding expression) ...) body ...)
(let ()
(define binding expression) ...
body ...))))
Using defmacro is more like making a procedure.
(define (my-let-fun* bindings . body)
...)
How it should work is like this:
(my-let-fun* '((a 1) (b 2) (c (+ a b))) "test" '(list a b c))
; ==> (let () (define a 1) (define b 2) (define c (+ a b)) "test" (list a b c))
If you have not called my-let-fun* in your implementation it's just changing it to a defmacro and you're done.
(defmacro my-let* (bindings . body)
...)
It's quite simple to do either with a helper to do recursion or foldr to do the bindings. Good luck!
Your my-let* will only work in #lang racket and perhaps #!r6rs and later. In R5RS you will get an error in this case:
(my-let* ((a 1) (b 2) (c (+ a b)))
(list a b c))
; signals an error that a is undefined.
The reason is that it expands to something like this:
(let ((a 'undefined) (b 'undefined) (c 'undefined))
(let ((tmp1 1) (tmp2 2) (tmp3 (+ a b)))
(set! a tmp1)
(set! b tmp2)
(set! c tmp3))
(list a b c))
Between the error messages and some judicious use of the macro stepper I think it's hard to go too wrong here. The trouble is just making sure you've put things together right using either conses or unquote-splicing. I believe the standard practice in such macros is heavy use of quasiquote and unquote-splicing in order for the output to as closely match the intended statement as possible, otherwise the macro can become quite inscrutable. But I am not a defmacro expert.
#lang racket/base
(require (for-syntax racket/base)
compatibility/defmacro)
(defmacro my-let* (binding-pairs . body)
(define defines (map (lambda (bp) (cons 'define bp)) binding-pairs))
`(let ()
,#defines
,#body))
(my-let* ((a 2)
(b (expt a 3)))
(printf "a:~a\nb:~a\n" a b)
(+ a b))
Consider the scenario where I would like to specify a very simplistic actor language using Racket macros. An actor is defined by a behaviour that defines some local state and message handlers that implement some logic. The body of a message handler can use both the formal parameters of the message, as well as the state variables. An example is implemented in the code below.
There is quite a lot of context in the code which is probably not even necessary. However, I have included it regardless in order to provide a running example, and the fact that I need to use syntax-parametrize may complicate the solution. The special point of interest is the with-syntax clause in the MESSAGE macro, where I require the (local-state-variable ...) pattern to match a list of identifiers, currently #'local-state-variables which is a list of symbols (bound by syntax-parameterize in the ACTOR macro), and thus does not match. So far I have not been able to find the solution, although it does not seem like it should be shockingly difficult. Am I missing something obvious?
#lang racket
(require (for-syntax syntax/parse))
(require racket/stxparam)
(define LOCAL_STATE
(lambda (stx)
(raise-syntax-error 'LOCAL_STATE "should only be used inside an actor" stx)))
; Define some syntax classes because abstractions are nice
(begin-for-syntax
(define-syntax-class actor-local-state
#:description "actor local state"
#:literals (LOCAL_STATE)
(pattern (LOCAL_STATE state-variable:id ...)))
(define-syntax-class message-pattern
#:description "actor message pattern"
(pattern (identifier:id argument:id ...))))
(define-syntax-parameter local-state-variables
(lambda (stx)
(raise-syntax-error 'local-state-variables "reserved keyword for actors" stx)))
(define-syntax (MESSAGE stx)
(syntax-parse stx
[(_ pattern:message-pattern body:expr ...+)
; Currently there is a "binding match failed" error on the following line, but replacing #'local-state-variables with #'(a b) (a list of identifiers) needless to say works.
(with-syntax ([(local-state-variable ...) #'local-state-variables])
; For simplicity just display the state variables - this is normally where some magic happens
#'(display '(local-state-variable ...)))]))
(define-syntax (ACTOR stx)
(syntax-parse stx
[(_ state:actor-local-state handler:expr ...+)
#'(syntax-parameterize
([local-state-variables '(state.state-variable ...)])
; For the sake of simplicity, an actor is currently a list of message handlers
(list handler ...))]))
; in this proof-of-concept code this should print (a b)
(define behaviour
(ACTOR (LOCAL_STATE a b)
(MESSAGE (add x y) (+ a b x y))))
Use syntax-parameter-value. Here's an example of using syntax parameters to manage lists of variables:
;; vars : syntax parameter of (Listof Identifier)
(define-syntax-parameter vars null)
;; with-vars: like let, but set vars
(define-syntax (with-vars stx)
(syntax-parse stx
[(_ ([var:id rhs:expr] ...) . body)
#'(let ([var rhs] ...)
(syntax-parameterize ([vars (list (quote-syntax var) ...)])
. body))]))
;; get-vars: get vars (symbolic name) and their values
(define-syntax (get-vars stx)
(syntax-parse stx
[(_)
(with-syntax ([(var ...) (syntax-parameter-value #'vars)])
#'(list (list (quote var) var) ...))]))
;; Examples:
(get-vars)
;; => '()
(with-vars ([x 1])
(get-vars))
;; => '((x 1))
(with-vars ([x 1])
(with-vars ([y 2] [z 3])
(set! z 17)
(get-vars)))
;; => '((y 2) (z 17))
The easiest way to turn any datum (including a list of symbol) into an identifier with datum->syntax. (You can also use format-id, but that works on only a single identifier.) With these functions, you pass in a syntax object for the scopes you want your new identifier to have, or #f if you want it to inherit the scopes that your current macro is generating.1 Getting your list of identifiers (as one single syntax object, would just be:
(syntax->datum stx '(a b c))
Where '(a b c) is your list of identifiers. Finally, you can then add this in your with-syntax:
(with-syntax ([(local-state-variables ...) (datum->syntax stx ...)])
...)
As a side note, the way to answer the title of your question, just iterate over your list with map producing a new list using format-id:
(map (curry format-id stx "~a") '(a b c)
1Unless I'm wrong, if so, please correct this.
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
Is there any way to detect if a macro is expanding inside a pattern match?
Here's an example macro that I'd like to write, but it fails inside a match-define:
#lang racket/base
(require racket/match (for-syntax racket/base syntax/parse))
(struct point (x y))
(define-syntax (friendly-point stx)
(syntax-parse stx
[(_ arg* ...)
#'(begin (printf "Now making a point\n") (point arg* ...))]
[_ #'(begin (printf "Hello point\n") point)]))
(define p (friendly-point 1 2))
;; Prints "Now making a point"
(match-define (friendly-point x y) p)
;; ERROR
Yes. Instead of using an ordinary syntax transformer created with define-syntax, use define-match-expander to create a macro that can cooperate with match.
(require (for-syntax syntax/parse))
(define-match-expander positive
(syntax-parser
[(_ n)
#'(? positive? n)]))
(match 3
[(positive n) (~a n " is positive")])
; => "3 is positive"
The define-match-expander form is flexible: it can be used to create macros that may only be used inside of match, but it can also be used to create macros that expand differently depending on how they are used by providing two transformer functions, one for each context. This allows you to have “context-sensitive” identifiers which work as both functions and as match expanders.
(require (for-syntax syntax/parse)
(prefix-in base: racket/base))
(define-match-expander syntax
(syntax-parser
[(_ x)
#'(? syntax? (app syntax->datum x))])
(make-rename-transformer #'base:syntax))
(match (syntax (1 2 3))
[(syntax n) (~a n " is a syntax list")])
If you need even more flexibility, you can forego define-match-expander entirely and define a custom struct with the prop:match-expander structure type property. This can be combined with prop:procedure to achieve the two-argument functionality described above, but it can also hold state, and it can be paired with other structure type properties such as prop:rename-transformer to allow the same identifier to function in many, many different contexts.
What you are looking for is define-match-expander. It allows you to make a macro that is expanded inside of a pattern matching context. (Also, because it takes in two thunks, you can have a variant that is also used when not in a matching context. Next, I should point out that
Next, you can have a printing side effect inside of the template of a define-match-expander, but you can have in the macro itself. (Note though that the side effect will not occur if your module has already been expanded. This is explain in more detail in this paper.
So, using match expanders, including a second function for use outside of match, you get the following code:
#lang racket/base
(require racket/match (for-syntax racket/base syntax/parse))
(struct point (x y))
(define-match-expander friendly-point
(lambda (stx)
(syntax-parse stx
[(_ arg* ...)
(printf "Now matching a point\n")
#'(point arg* ...)]
[_ #'point]))
(lambda (stx)
(syntax-parse stx
[(_ args* ...)
#'(begin (printf "Now making a point\n") (point args* ...))])))
(define p (friendly-point 1 2))
;; Prints "Now making a point"
(match-define (friendly-point x y) p)
;; Works fine now