TL;DR - your version of the macro seems to do the trick. Thank you.
On Monday, July 20, 2020 at 3:56:33 AM UTC-4, Maciek Godek wrote:
It is unclear to me what is the goal of your macro.
Could you give some example usages (and their expected expansions)?
OK, the big picture first. The program in question is a sample meta-circular evaluator for a Scheme sub-set, from the first chapter of a book titled _Lisp in Small Pieces_ (the author's page for the book is at
https://christian.queinnec.org/WWW/LiSP.html)
. For didactic reasons, I am not copying the code exactly, as I want to be certain I've understood the ideas correctly.
In the original code (which IIUC was written for R4RS, though I am using a variant form of R5RS right now), the program environments are represented as simple lists of key-value pairs. To add a primitive non-special form (a function in the underlying
Scheme used for the implementation), it has a macro, (define-primitive), which in turn invokes another macro, (define-initial), that adds a key-value pair to the global environment.
The main reason for (define-primitive), aside from simplifying the process of defining a form as opposed to a constant or global variable, is to wrap the value part (the procedure itself) in a lambda which tests whether the arity of a given procedure
call is correct.
My versions of these two macros are:
--------------------------------------------------------
(define-syntax define-initial
(lambda (macro)
(syntax-case macro (in)
((_ <name> <value> in <env>)
(identifier? #'<name>)
#`(begin
(set! <env> (cons (cons '<name> <value>) <env>))
'<name>))
((_ <name> <value>)
#`(define-initial <name> <value> in env.global))
((_ <name> in <env>)
#`(define-initial <name> void in <env>))
((_ <name>)
#`(define-initial <name> void in env.global)))))
(define-syntax define-primitive
(lambda (macro)
(syntax-case macro (in)
((_ <name> <primitive> <arity> in <env>)
#`(define-initial <name>
(lambda (values)
(if (= <arity> (length values))
(apply <primitive> values)
(begin
(display "PROCEDURE-APPLICATION: Incorrect arity for fn")
(display <name>)
(display ": expect ")
(display <arity>)
(display ", got ")
(display (length values)))))
in <env>))
((_ <name> <primitive> <arity>)
#`(define-primitive <name> <primitive> <arity> in env.global))
((_ <primitive-name> <arity> in <env>)
#`(define-primitive <primitive-name> <primitive-name> <arity> in <env>))
((_ <primitive-name> <arity>)
#`(define-primitive <primitive-name> <arity> in env.global))))) --------------------------------------------------------
My macro, (define-primitives-by-arity), is just syntactic sugar to simplify bulk definitions of basic forms such as plus, cons, car, cdr, etc. to be define all at once, based on their arity. For example:
-------------------------------------------------------- (define-primitives-by-arity 0 exit)
(define-primitives-by-arity 1
null? procedure? pair? number? integer? symbol?
car cdr)
(define-primitives-by-arity 2 + - * / cons) --------------------------------------------------------
The intent (as you seem to have guessed below) is to expand into a series of invocations of (define-primitive), in which the <arity> argument is constant for all of the newly-defined primitives. The result of that first expansion should be something like
this:
--------------------------------------------------------
(define-primitive exit 0)
(define-primitive null? 1)
(define-primitive procedure? 1)
(define-primitive pair? 1)
[...]
(define-primitive / 2)
(define-primitive cons 2) --------------------------------------------------------
As you can see, this would be trivial to do by hand anyway, so the macro is just syntactic sugar, but I expect that it would help later on down the road as I proceed with the textbook.
However, I am guessing that the definition you might be looking for is
(define-syntax-rule (define-primitives-by-arity arity primitives ...)
(begin
(define-primitive primitives arity)
...))
Ah, thank you, this does exactly what I needed.
I'm still unclear on why it works, and mine didn't, but I suspect I was just overthinking things. Part of the problem is that I'd set this project aside for about two years, and I am only just getting back to it now, so I don't exactly remember what my
logic for it was.
Also, I am used to (define-syntax-rule) always having a (syntax-rules) clause, whether or not it is used, but I can only assume from this that the clause is optional (only needed if the macro has more than one pattern to match, I take it). Am I
understanding this correctly?
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)