defining macro-generated macros that take in variable number of arguments - racket

I am trying to write a macro-generating macro, where the macro it generates takes a variable number of arguments.
I am wondering if there is a way to make the following code work:
(define-syntax-rule (greet name)
(define-syntax-rule (name args ...)
(printf "hello ~a~n" (list args ...))))
Right now it says "no pattern variables before ellipsis in template in: ..."
If I take the inner define-syntax-rule by itself it works fine, so why doesn't it work when it's being generated by another macro?

There are at least 3 "Styles" of doing this.
1: Ellipsis-quoting each ellipsis separately
Soegaard already answered that you can replace every ... in the body with (... ...), so that it gets interpreted as a literal ellipsis belonging to the inner macro instead of as a "meta" ellipsis belonging to the outer macro:
(define-syntax-rule (greet name)
(define-syntax-rule (name args (... ...))
(printf "hello ~a~n" (list args (... ...)))))
Advantages: Flexible, you can mix literal (... ...) and meta ... ellipses freely within the body
Disadvantages: Looks confusing if you haven't seen (... ...) before
2: Ellipsis-quoting the whole inner macro definition
However, putting (... <something>) around something is not limited to just .... If you put a whole template there, any ...s within that template will also be "quoted", treated as literal instead of meta, in the same way:
(define-syntax-rule (greet name)
(...
(define-syntax-rule (name args ...)
(printf "hello ~a~n" (list args ...)))))
Advantages: If you have even greater nesting depths you wouldn't need ((... ...) (... ...)) as you would with option 1, you would just need (... <something-containing (... <something>)>)
Disadvantages: Rigid, if you put (... <something>) around something you can't ever use a meta ellipsis inside that something. You can't mix literal and meta ellipses freely like you could with style 1 or 3.
3: Creating a pattern-variable to represent a literal ellipsis
Here's another way, which I find less confusing, but it requires using define-simple-macro instead of define-syntax-rule, so that you can bind new pattern variables using #:with.
(require syntax/parse/define)
(define-simple-macro (<name> <arguments>)
#:with <pattern-variable> <expression>
<body-expression>)
You can use with #:with to bind an ooo pattern variable to a literal ellipsis: #:with ooo (quote-syntax ...)
(require syntax/parse/define)
(define-simple-macro (greet name)
#:with ooo (quote-syntax ...)
(define-syntax-rule (name args ooo)
(printf "hello ~a~n" (list args ooo))))
Advantages: Flexible, you can mix literal ooo and meta ... ellipses freely within the body. To me, it looks less confusing than (... ...) or ((... ...) (... ...)).
Disadvantages: For deeper nesting, you might need multiple #:with-definitions, one on each meta-level.

The ... belongs to the outer define-syntax-rule. In order
to produce an ellipsis in the output you need to quote it with (... ...).
(define-syntax-rule (greet name)
(define-syntax-rule (name args (... ...))
(printf "hello ~a~n" (list args (... ...)))))
For fun: If you ever need to write a macro that produces a macro that produces a macro, you will need ((... ...) (... ...)) to produce an ellipsis.

Related

How can I modify the #+ and #- readtable macros in Lisp?

Short version:
I want to change the #+ and #- reader macros to apply to all immediately subsequent tokens starting with ##, in addition to the following token. Therefore, the following code...
#+somefeature
##someattribute1
##someattribute2
(defun ...)
...would, in the absence of somefeature, result in no code.
Long version:
I have written my own readtable-macros which apply transformations to subsequent code. For example:
##traced
(defun ...)
This yields a function that writes its arguments and return values to a file, for debugging.
This fails, however, when used in conjunction with the #+ reader macro:
#+somefeature
##traced
(defun ...)
In the absence of somefeature, the function continues to be defined, albeit without the ##traced modification. This is obviously not the desired outcome.
One possible solution would be to use progn, as follows:
#+somefeature
(progn
##traced
(defun ...))
But that's kind of ugly.
I would like to modify the #+ and #- reader macros, such that they may consume more than one token. Something like this:
(defun conditional-syntax-reader (stream subchar arg)
; If the conditional fails, consume subsequent tokens while they
; start with ##, then consume the next token.
)
(setf *readtable* (copy-readtable))
(set-dispatch-macro-character #\# #\+ #'conditional-syntax-reader)
(set-dispatch-macro-character #\# #\- #'conditional-syntax-reader)
The problem is, I don't know how to "delegate" to the original reader macros; and I don't understand enough about how they were implemented to re-implement them myself in their entirety.
A naive approach would be:
(defun consume-tokens-recursively (stream)
(let ((token (read stream t nil t)))
(when (string= "##" (subseq (symbol-string token) 0 2))
(consume-tokens-recursively stream)))) ; recurse
(defun conditional-syntax-reader (stream subchar arg)
(unless (member (read stream t nil t) *features*)
(consume-tokens-recursively stream)))
However, I'm given to believe that this wouldn't be sufficient:
The #+ syntax operates by first reading the feature specification and then skipping over the form if the feature is false. This skipping of a form is a bit tricky because of the possibility of user-defined macro characters and side effects caused by the #. and #, constructions. It is accomplished by binding the variable read-suppress to a non-nil value and then calling the read function.
This seems to imply that I can just let ((*read-suppress* t)) when using read to solve the issue. Is that right?
EDIT 1
Upon further analysis, it seems the problem is caused by not knowing how many tokens to consume. Consider the following attributes:
##export expects one argument: the (defun ...) to export.
##traced expects two arguments: the debug level and the (defun ...) to trace.
Example:
#+somefeature
##export
##traced 3
(defun ...)
It turns out that #+ and #- are capable of suppressing all these tokens; but there is a huge problem!
When under a suppressing #+ or #-, (read) returns NIL!
Example:
(defun annotation-syntax-reader (stream subchar arg)
(case (read stream t nil t)
('export
(let ((defun-form (read stream t nil t)))))
; do something
('traced
(let* ((debug-level (read stream t nil t))
(defun-form (read stream t nil t)))))))
; do something
(setf *readtable* (copy-readtable))
(set-dispatch-macro-character #\# #\# #'annotation-syntax-reader)
#+(or) ##traced 3 (defun ...)
The ##traced token is being suppressed by the #+. In this situation, all the (read) calls in (annotation-syntax-reader) consume real tokens but return NIL!
Therefore, the traced token is consumed, but the case fails. No additional tokens are thus consumed; and control leaves the scope of the #+.
The (defun ...) clause is executed as normal, and the function comes into being. Clearly not the desired outcome.
The standard readtable
Changing the macros for #+ and #- is a bit excessive solution I think, but in any case remember to not actually change the standard readtable (as you did, but its important to repeat in the answer)
The consequences are undefined if an attempt is made to modify the standard readtable. To achieve the effect of altering or extending standard syntax, a copy of the standard readtable can be created; see the function copy-readtable.
§2.1.1.2 The Standard Readtable
Now, maybe I'm missing something (please give us a hint about how your reader macro is defined if so), but I think it is possible to avoid that and write your custom macros in a way that works for your use case.
Reader macro
Let's define a simple macro as follows:
CL-USER> (defun my-reader (stream char)
(declare (ignore char))
(let ((name (read stream)
(form (read stream))
(unless *read-suppress*
`(with-decoration ,name ,form)))
MY-READER
[NB: This was edited to take into account *read-suppress*: the code always read two forms, but returns nil in case it is being ignored. In the comments you say that you may need to read an indefinite number of forms based on the name of the decoration, but with *read-suppress* the recursive calls to read return nil for symbols, so you don't know which decoration is being applied. In that case it might be better to wrap some arguments in a literal list, or parse the stream manually (read-char, etc.). Also, since you are using a dispatching macro, maybe you can add a numerical argument if you want the decoration to be applied to more than one form (#2#inline), but that could be a bad idea when later the decorated code is being modified.]
Here the reader does a minimal job, namely build a form that is intended to be macroexpanded later. I don't even need to define with-decoration for now, as I'm interested in the read step. The intent is to read the next token (presumably a symbol that indicates what decoration is being applied, and a form to decorate).
I'm binding this macro to a unused character:
CL-USER> (set-macro-character #\§ 'my-reader)
T
Here when I test the macro it wraps the following form:
CL-USER> (read-from-string "§test (defun)")
(WITH-DECORATION TEST (DEFUN))
13 (4 bits, #xD, #o15, #b1101)
And here it works with a preceding QUOTE too, the apostrophe reader grabs the next form, which recursively reads two forms:
CL-USER> '§test (defun)
(WITH-DECORATION TEST (DEFUN))
Likewise, a conditional reader macro will ignore all the next lines:
CL-USER> #+(or) t
; No values
CL-USER> #+(or) §test (defun)
; No values
CL-USER> #+(or) §one §two §three (defun)
; No values
Decoration macro
If you use this syntax, you'll have nested decorated forms:
CL-USER> '§one §two (defun test ())
(WITH-DECORATION ONE (WITH-DECORATION TWO (DEFUN TEST ())))
With respect to defun in toplevel positions, you can arrange for your macros to unwrap the nesting (not completely tested, there might be bugs):
(defun unwrap-decorations (form stack)
(etypecase form
(cons (destructuring-bind (head . tail) form
(case head
(with-decoration (destructuring-bind (token form) tail
(unwrap-decorations form (cons token stack))))
(t `(with-decorations ,(reverse stack) ,form)))))))
CL-USER> (unwrap-decorations ** nil)
(WITH-DECORATIONS (ONE TWO) (DEFUN TEST ()))
And in turn, with-decorations might know about DEFUN forms and how to annotate them as necessary.
For the moment, our original macro is only the following (it needs more error checking):
(defmacro with-decoration (&whole whole &rest args)
(unwrap-decorations whole nil))
For the sake of our example, let's define a generic annotation mechanism:
CL-USER> (defgeneric expand-decoration (type name rest))
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::EXPAND-DECORATION (0)>
It is used in with-decorations to dispatch on an appropriate expander for each decoration. Keep in mind that all the efforts here are to keep defun in a top-level positions (under a progn), a recursive annotation would let evaluation happens (in the case of defun, it would result in the name of the function being defined), and the annotation could be done on the result.
The main macro is then here, with a kind of fold (reduce) mechanism where the forms are decorated using the resulting expansion so far. This allows for expanders to place code before or after the main form (or do other fancy things):
(defmacro with-decorations ((&rest decorations) form)
(etypecase form
(cons (destructuring-bind (head . tail) form
(ecase head
(defun (destructuring-bind (name args . body) tail
`(progn
,#(loop
for b = `((defun ,name ,args ,#body)) then forms
for d in decorations
for forms = (expand-decoration d name b)
finally (return forms))))))))))
(nb. here above we only care about defun but the loop should probably be done outside of the dispatching thing, along with a way to indicate to expander methods that a function is being expanded; well, it could be better)
Say, for example, you want to declare a function as inline, then the declaration must happen before (so that the compiler can know the source code must be kept):
(defmethod expand-decoration ((_ (eql 'inline)) name rest)
`((declaim (inline ,name)) ,#rest))
Likewise, if you want to export the name of the function being defined, you can export it after the function is defined (order is not really important here):
(defmethod expand-decoration ((_ (eql 'export)) name rest)
`(,#rest (export ',name)))
The resulting code allows you to have a single (progn ...) form with a defun in toplevel position:
CL-USER> (macroexpand '§inline §export (defun my-test-fn () "hello"))
(PROGN
(DECLAIM (INLINE MY-TEST-FN))
(DEFUN MY-TEST-FN () "hello")
(EXPORT 'MY-TEST-FN))

Lisp - optional argument in the middle of parameter list

I currently have a macro defined as follows:
(defmacro some-macro (generic-name (&rest args) &body body)
...)
I would now like to add an extra parameter to this macro, a kind of flag which a user can optionally provide and which would alter the behavior of the macro. The below code should be possible:
(some-macro some-name (arg1 arg2) (print (+ arg1 arg2)))
(some-macro :flag some-name (arg1 arg2) (print (special-+ arg1 arg2)))
I intentionally just made a conceptual example to focus on what's important instead of the real macro I'm trying to implement. The real a macro is different and more complex. As you can see, the macro should now be callable with both the :flag argument (flag can be any word, as long as its prefix is ':') and without the flag argument. Is there a way to do this without positioning the &optional keyword at the end of the parameter list (ie. it really needs to be at that first position).
&optional can only be at the end of the positional arguments (you can have &rest or &body after it). Even if you could put it earlier, if there's also &rest or &body, how would it know whether you provided the optional argument? E.g. if the lambda list were
(&optional arg1 arg2 &rest rest-args)
and the call were
(func-name 1 2 3 4 5)
it could either be arg1 = 1, arg2 = 2, rest-args = (3 4 5) or arg1 = NIL, arg2 = 1, rest-args = (2 3 4 5).
You'll need to define the macro to take a single &rest argument. Then you can check whether the first argument is a keyword or not, update the argument list to add the default, and then parse it with destructuring-bind.
(defmacro some-macro (&rest all-args)
(unless (keywordp (first all-args))
(push nil all-args)) ;; flag defaults to NIL
(destructuring-bind (flag generic-name (&rest args) &body body) all-args
...))
(some-macro :flag some-name (arg1 arg2) (print (special-+ arg1 arg2)))
(some-macro some-name (arg1 arg2) (print (+ arg1 arg2)))
One can only guess what's useful, since the design of the macro depends a bit on more context: what is it actually used for.
For example in CLOS we write
(defmethod foo :around ((a class-a)) ...)
The name comes first, then zero or more method-qualifiers (here :around and then the arglist. Putting a flag in front of a name would be strange in typical defining macros (those who begin with def).
For that we would need to write the macro-destructuring of the arglist ourselves, since it does not match a built-in macro arglist pattern.
(defmacro some-macro (name &rest args)
(let* ((qualifiers (loop for arg in args
until (listp arg)
collect (pop args)))
(arg-list (pop args))
(body args))
... ; return something for the example
))
In other macros we might write
(some-macro some-name (arg1 arg2 :flag)
(print (special-+ arg1 arg2)))
(defmacro some-macro (some-name (arg1 arg2 &optional flag) &body body)
...)
Similar for example to
(with-input-from-string (stream string :start 10)
(... ))
Though above uses keywords, not optionals.
Or we might want to write:
(some-macro some-name (arg1 arg2) (:flag1)
(print (special-+ arg1 arg2)))
(defmacro some-macro (some-name (&rest args) (&rest flags) &body body)
...)
If there are only three flags one can also generate three different macros with different names and remove the flag.
One thing to think about when designing things like macros (and, remember, when you are designing macros, you are designing a programming language) is how people expect to read the language. If the programming language you are designing is a mild superset of CL, or is otherwise very close to CL, then you may want to not violate the expectations CL programmers have when reading CL code, or more generally that Lisp programmers have when reading Lisp code.
[Note that most of what follows is opinion: people obviously have different opinions – these are mine, they're not more right than anyone else's.]
So, what are those expectations? Well, they may include the following two:
people read CL left-to-right, so the things at the left-hand end of a form tend to be more visually important;
many existing forms in CL look like (<operator> <thing> ...) – the first two subforms in the form are by far the most interesting, and the second is often more interesting than the first. Think about (defun foo ...), (dolist (x ...) ...), (let ((x y) ...) ...).
An example of something which violates these expectations is an object system which works explicitly with message-passing, using some send operation (I think Old Flavors did this, and I think that New Flavors didn't, but my memory is vague now). Code written using these looks like (send <object> <message> ...): the first word in many forms is send. That means that this visually-important place for reading code has been entirely wasted as it is always the same word and the important places are now the second and third subform. Well, instead, we could just omit the whole send thing and write (message object ...) or (object message ...). CLOS takes essentially the first of these options, where a 'message' is a generic function and of course generic functions can specialise on more than one argument which breaks the whole message-passing paradigm. But you can write CLOS as if it was message-passing, and it works, and it means that it agrees with how a lot of other CL code looks.
So, OK let's look at two cases of your macro:
(some-macro some-name ...)
This is fine.
(some-macro :flag some-name ...)
But this has filled the visual second-position slot with something which is not whatever the macro is about: it's just some optional argument. The interesting thing is now the third position.
Well, how could we fix this? It turns out there is a good example which already exists in CL: defstruct. defstruct has two basic cases:
(defstruct structure-name
...)
and
(defstruct (structure-name ...)
...)
Both of these meet the first-two-positions-matter-most requirement, while allowing optional arguments and clearly visually indicating when they are used.
(Aside: defclasss does things differently by putting the options at the end as in:
(defclass name (...supers...)
(...slot specifications...)
...options...))
Either is OK I think.)
So one way to redo your macro would be like defstruct. In this case you would have one of
(some-macro some-name (...)
...)
or
(some-macro (some-name :flag) (...)
...)
And you could implement that pretty easily:
(defmacro some-macro (thing (&rest args) &body forms)
(multiple-value-bind (the-thing the-options)
(etypecase thing
(symbol (values thing '()))
(cons
(destructuring-bind (proposed-name . proposed-options) thing
(unless (symbolp proposed-name)
(error ...))
(unless (proper-list-p proposed-options)
(error ...))
(values proposed-name proposed-options))))
...))
In fact I would go further than this: people expect keyword arguments to have values, because in most other places they do. So instead have
(some-macro (some-name :flag t) (...)
...)
Which meets that expectation. This has the additional advantage that you can just use CL's argument parsing to get information:
> (destructuring-bind (&key (flag nil flagp)) '(:flag t)
(values flag flagp))
t
t
For instance. If you write the macro like this you might end up with something which looks like this:
(defmacro some-macro (thing (&rest args) &body forms)
(multiple-value-bind (the-thing flag flagp)
(etypecase thing
(symbol (values thing nil nil))
(cons
(destructuring-bind (proposed-name (&key (flag nil flagp))) thing
(unless (symbolp proposed-name)
(error ...))
(values proposed-name flag flagp))))
...))
As an aside it's worth considering why defclass & defstruct do things differently, and what this means for other macros.
defstruct looks, in outline, like
(defstruct structure-name-and-options
slot-description
...)
What this means is that, if you put options associated with the structure itself at the end, they're going to get confused with slot descriptions.
defclass gets around this by looking like this:
(defclass class-name (superclass-name ...)
(slot-description
...)
[class-option] ...)
It has nested the slot descriptions inside another list, which means that there is now space in the pattern for class options at the end of the form.
For macros which have some kind of 'body', then the natural pattern looks like
(with-foo something [some-more-special-things] ...
form
...)
For example
(with-slots (sa sb) x
(when (> sa sb)
(setf sb (+ sa sb)))
(values sa sb))
The problem here is that the whole tail of the macro form is the body which means that there is no natural place for options at the end: the only place to put them is at the beginning somewhere. You could get around this, again, by nesting the body:
(with-weird-thing x (y z)
((when y
...)
(print z)
...)
option ...)
But this, again, violates people's expectations: no (?) standard CL macros do this. It's significant that defclass's 'body' is not some forms: it's a list of slot specifications. So it's reasonable to adopt this pattern for defclass.
Finally it's worth considering defmethod. If I had designed this I would have done it slightly differently!
No-nonsense approach: rewrite the macro syntax with flags into another macro which takes a fixed argument containing the flags:
(defmacro some-macro-w-flags (flags name (&rest args) &body body)
...)
(defmacro some-macro (&rest args)
(let ((flags))
(loop while (keywordp (car args))
do (push (pop args) flags))
`(some-macro-w-flags ,flags ,#args)))
A few tests:
[1]> (macroexpand-1 '(some-macro abc (1 2 3)))
(SOME-MACRO-W-FLAGS NIL ABC (1 2 3)) ;
T
[2]> (macroexpand-1 '(some-macro :foo abc (1 2 3)))
(SOME-MACRO-W-FLAGS (:FOO) ABC (1 2 3)) ;
T
[3]> (macroexpand-1 '(some-macro :foo :bar abc (1 2 3)))
(SOME-MACRO-W-FLAGS (:BAR :FOO) ABC (1 2 3)) ;
T

registering a function in a list as it is being defined

I am trying to make a list of callback functions, which could look like this:
(("command1" . 'callback1)
("command2" . 'callback2)
etc)
I'd like it if I could could do something like:
(define-callback callback1 "command1" args
(whatever the function does))
Rather than
(defun callback1 (args)
(whatever the function does))
(add-to-list 'callback-info ("command1" . 'callback1))
Is there a convenient way of doing this, e.g., with macros?
This is a good example of a place where it's nice to use a two-layered approach, with an explicit function-based layer, and then a prettier macro layer on top of that.
Note the following assumes Common Lisp: it looks just possible from your question that you are asking about elisp, in which case something like this can be made to work but it's all much more painful.
First of all, we'll keep callbacks in an alist called *callbacks*:
(defvar *callbacks* '())
Here's a function which clears the alist of callbacks
(defun initialize-callbacks ()
(setf *callbacks* '())
(values)
Here is the function that installs a callback. It does this by searching the list to see if there is a callback with the given name, and if there is then replacing it, and otherwise installing a new one. Like all the functions in the functional layer lets us specify the test function which will let us know if two callback names are the same: by default this is #'eql which will work for symbols and numbers, but not for strings. Symbols are probably a better choice for the names of callbacks than strings, but we'll cope with that below.
(defun install-callback (name function &key (test #'eql))
(let ((found (assoc name *callbacks* :test test)))
(if found
(setf (cdr found) function)
(push (cons name function) *callbacks*)))
name)
Here is a function to find a callback, returning the function object, or nil if there is no callback with that name.
(defun find-callback (name &key (test #'eql))
(cdr (assoc name *callbacks* :test test)))
And a function to remove a named callback. This doesn't tell you if it did anything: perhaps it should.
(defun remove-callback (name &key (test #'eql))
(setf *callbacks* (delete name *callbacks* :key #'car :test test))
name)
Now comes the macro layer. The syntax of this is going to be (define-callback name arguments ...), so it looks a bit like a function definition.
There are three things to know about this macro.
It is a bit clever: because you can know at macro-expansion time what sort of thing the name of the callback is, you can decide then and there what test to use when installing the callback, and it does this. If the name is a symbol it also wraps a block named by the symbol around the body of the function definition, so it smells a bit more like a function defined by defun: in particular you can use return-from in the body. It does not do this if the name is not a symbol.
It is not quite clever enough: in particular it does not deal with docstrings in any useful way (it ought to pull them out of the block I think). I am not sure this matters.
The switch to decide the test uses expressions like '#'eql which reads as (quote (function eql)): that is to avoid wiring in functions into the expansion because functions are not externalisable objects in CL. However I am not sure I have got this right: I think what is there is safe but it may not be needed.
So, here it is
(defmacro define-callback (name arguments &body body)
`(install-callback ',name
,(if (symbolp name)
`(lambda ,arguments
(block ,name
,#body))
`(lambda ,arguments
,#body))
:test ,(typecase name
(string '#'string=)
(symbol '#'eql)
(number '#'=)
(t '#'equal))))
And finally here are two different callbacks being defined:
(define-callback "foo" (x)
(+ x 3))
(define-callback foo (x)
(return-from foo (+ x 1)))
These lists are called assoc lists in Lisp.
CL-USER 120 > (defvar *foo* '(("c1" . c1) ("c2" . c2)))
*FOO*
CL-USER 121 > (setf *foo* (acons "c0" `c1 *foo*))
(("c0" . C1) ("c1" . C1) ("c2" . C2))
CL-USER 122 > (assoc "c1" *foo* :test #'equal)
("c1" . C1)
You can write macros for that, but why? Macros are advanced Lisp and you might want to get the basics right, first.
Some issues with you example you might want to check out:
what are assoc lists?
what are useful key types in assoc lists?
why you don't need to quote symbols in data lists
variables are not quoted
data lists need to be quoted
You can just as easy create such lists for callbacks without macros. We can imagine a function create-callback, which would be used like this:
(create-callback 'callback1 "command1"
(lambda (arg)
(whatever the function does)))
Now, why would you use a macro instead of a plain function?
In the end, assisted by the responders above, I got it down to something like:
(defmacro mk-make-command (name &rest body)
(let ((func-sym (intern (format "mk-cmd-%s" name))))
(mk-register-command name func-sym)
`(defun ,func-sym (args &rest rest)
(progn
,#body))))

Common Lisp Lisp-1 macro

I am trying to emulate the single namespace of scheme within common lisp, with a macro (based on Doug Hoyte's) that expands to a lambda, where every use of an f! symbol (similar to Doug Hoyte's o! and g! symbols) in the function position expands to the same expression, but with funcall added in the function position of each invocation. For example:
(fplambda (f!z x) (f!z x x))
would expand to:
(LAMBDA (F!Z X) (FUNCALL F!Z X X))
The macro currently looks like this:
(defmacro fplambda (parms &body body)
(let ((syms (remove-duplicates
(remove-if-not #'f!-symbol-p
(flatten body)))))
`(lambda ,parms
(macrolet ,(mapcar
(lambda (f)
`(,f (&rest parmlist) `(funcall ,',f ',#parmlist)))
syms))
,#body)))
but given the above input, it expands (as far as I can see) to this:
(LAMBDA (F!F X)
(MACROLET ((F!F (&REST PARMLIST) `(FUNCALL ,'F!F ',#PARMLIST))))
(F!F X X))
In the macrolet definition, F!F should not be quoted or unquoted, and parmlist should just be unquoted. What is going on?
Thanks in advance!
Your definition is mostly right. You just made two pretty simple mistakes. The first one being a mismatched paren. The macrolet does not include the body (in the output the macrolet and the body are at the same level of indentation).
As for the nested backquote, the only mistake is the quote before parmlist. Other than that everything else is correct. The comma and quote before F!F is actually correct. From the hyperspec:
"An implementation is free to interpret a backquoted form F1 as any form F2 that, when evaluated, will produce a result that is the same under equal as the result implied by the above definition". Since the inner backquote has not been expanded yet, it does not have to be free of quotes and unquotes. The expression `(,'x) is actually the same as `(x).
Nested backquotes are notoriously complicated. What is probably the easiest way to understand them is to read Steele's explanation of them.
Edit:
The answer to your question about whether it is possible to use a fplambda expression in the function position is no. From the part of the hyperspec that deals with the evaluation of code: "If the car of the compound form is not a symbol, then that car must be a lambda expression, in which case the compound form is a lambda form.". Since the car of the form, (fplambda ...), is not a lambda expression, your code is no longer valid Common Lisp code.
There is a workaround to this that I figured out, but it's kind of ugly. You can define a reader macro that will allow you to write something like ([fplambda ...] ...) and have it read as
((LAMBDA (&REST #:G1030) (APPLY (FPLAMBDA ...) #:G1030)) ...)
which would do what you want. Here is code that will allow you to do that:
(set-macro-character #\[ 'bracket-reader)
(set-macro-character #\] (get-macro-character #\)))
(defun bracket-reader (stream char)
"Read in a bracket."
(declare (ignore char))
(let ((gargs (gensym)))
`(lambda (&rest ,gargs)
(apply ,(read-delimited-list #\] stream t)
,gargs))))
The only other solution I can think of would be to use some sort of code walker (I can't help you there).

Generating logging information using Racket

Background:
I intend to generate debug messages for the code I'm developing. I wrote a macro to avoid writing the logging calls in each function. I know this limits the ability to generate more customized debug messages, but in return it isolates logging from code. And that is what I'm aiming for. This macro approach has other drawbacks too, for example it limits creation of function bindings to this macro only, but I think I can live with that.
Following is the definition of the macro and an example demonstrating its usage.
(define-syntax (define-func stx)
(syntax-case stx ()
[(define-func (func-name args ...) body1 body2 ...)
(if (and (identifier? #'func-name)
(andmap symbol? (syntax->datum #'(args ...))))
(syntax (define (func-name args ...)
(log-debug (format "Function-name ~a:" (syntax-e #'func-name)) (list args ...))
body1
body2 ...))
(raise-syntax-error 'define-func "not an identifier" stx))]
[else (raise-syntax-error 'define-func "bad syntax" stx)]))
(define-func (last l)
(cond [(null? l) null]
[(null? (rest l)) (first l)]
[else (last (rest l))]))
(define-func (main)
(last (list 1 2 3 4 5 6 7 8 9))
(logger))
log-debug and logger are defined in separate module
The output produced is somewhat like following:
Function-name last:
args:
:-> (7 8 9)
Function-name last:
args:
:-> (8 9)
Function-name last:
args:
:-> (9)
Now I want to make it more readable. By readability I mean to provide some kind of indentation so that the person reading the log could make sense of call flow. For example something like following:
Function-name last:
args:
:-> (7 8 9)
Function-name last:
args:
:-> (8 9)
Function-name last:
args:
:-> (9)
It is easier to figure out who called whom and so forth. I have an idea that can do this. It involves a variable that keeps track of indentation then after logging the function name I will increase the indent and after evaluation of body and before returning the value decrements the value. Something like following:
(define indent 0)
(define-syntax (define-func stx)
(syntax-case stx ()
[ (... ...)
(...
(log-debug ...)
(increment indent)
(let [(retval (body1 body2 ...)]
(decrease indent)
retval))]))
increment and decrease increases and decreases indentation respectively.
Problem:
It works even for function that returns void. I'm not sure whether its the correct behavior. In racket void is a special value, but I'm not sure that creating a binding to void is right way to go.
Is there any better way to achieve the same? If not are there any problems in this design? I'm open to any idea/change as long as they keep the logging and code separate.
thanks for the help!
I have several suggestions for you:
It's probably better to use a parameter instead of a variable, for "global" stuff like your indentation level, since the original value is restored for you at the end of the parameterize expression.
All those raise-syntax-error checks you have in your macro are totally superfluous: syntax-case already provides guards (also known as fenders) that allow you to do any validation of macro "arguments" necessary:
(define-syntax (define-func stx)
(syntax-case stx ()
[(_ (func-name args ...) body1 body2 ...)
(andmap identifier? (syntax->list #'(func-name args ...)))
#'(define (func-name args ...)
(log-debug (format "Function-name ~a:" 'func-name)
(list args ...))
body1
body2 ...)]))
I've also fixed up your code in several places, as you can see above:
I used (_ ...) instead of (define-func ...), since in syntax-case (unlike syntax-rules), the latter will actually bind a pattern variable called define-func, which will affect any recursive macro calls you may want to do (I'll grant that you don't have one here, but it's a good habit to have anyway).
Rather than completely flatten the #'(args ...) in the guard, I just turned it into a list of syntax objects so you can test using identifier?. This is more intention-revealing than testing using symbol?, and allows us to also test func-name in the same expression.
You don't need to use (syntax-e #'func-name) inside the expanded code! Just quote it.