Why doesn't Dr. Racket expand nested macros? - macros

I am using Dr. Racket, version 5.3.1. I am trying to use the Macro Stepper feature, and am having problems with "nested" macros. (By "nested" macros, I mean macros that expand to a form which contains more (used-defined) macros. I don't know if this is the correct terminology). The macro stepper only expands these macros once, and then doesn't bother to continue expanding.
For example, I type the following into the Dr. Racket definitions area:
#lang racket
(define-syntax foo
(syntax-rules ()
((foo a) 1)
((foo a stuff ...) (+ 1 (foo stuff ...)))))
(foo a b c d e)
Running this returns 5, as expected. Furthermore, typing (expand '(foo a b c d e)) in the Interactions window yields the syntax '(#%app + '1 (#%app + '1 (#%app + '1 (#%app + '1 '1)))), also as expected. However, going into the Macro Stepper (with standard macro hiding) and pressing the End button, I only see (+ 1 (foo b c d e)). If I disable macro hiding, I get the expected result, but also a whole lot of line noise that I'd rather not see.
Is this a bug, or expected behaviour? I swear that Dr. Racket didn't used to behave like this...
I actual submitted a bug report about this a month ago (http://bugs.racket-lang.org/query/?cmd=view&pr=13203), but then I started having second thoughts about whether it was a bug or not, so I decided to ask here.
PS - other random notes about this:
It seems to depend on whether or not the nested macro is the outer-most expression in the expanded form. For example, if I define (in addition to foo):
(define-syntax bar
(syntax-rules ()
((bar xs ...) (foo xs ...))))
(define-syntax baz
(syntax-rules ()
((baz xs ...) (bar xs ...))))
(baz a b c d e)
Then the macro stepper shows me that (baz a b c d e) expands to (bar a b c d e) to (foo a b c d e) to (+ 1 (foo b c d e)), but then it stops.
The previous example might make you think it has something to do with macros that expand to themselves, but this doesn't appear to be the case. For example, if I redefine foo as follows:
(define-syntax foo
(syntax-rules ()
((foo a) 1)
((foo a stuff ...) (+ 1 (blah stuff ...)))))
With
(define-syntax blah
(syntax-rules ()
((blah xs ...) 10)))
Then (foo a b c d e) expands to (+ 1 (blah b c d e)) and then stops.

I'm not sure if this is a bug or not, although the foo in the expanded code is a different color then the original foo, so I'm inclined to think that is what is confusing it.
By default, the macro stepper tries to simplify the expanded macro to show only macros defined in the module, and files required with strings (i.e. files from your 'project'). This is the feature that seems to be throwing it off.
One way you can work around this (at least in smallish files) is to disable this feature. To do this, go to the bottom left of the window where it says: Macro hiding:, click the drop down menu and select Disable.
Macro hiding: -> Disable
From there, you should see the entire expansion of your module, including the expansion of foo.

Related

Emacs + cider: Autocomplete defprotocol methods. Possible or not?

Is it possible to have autocompletion of defprotocol methods in Emacs?
An example:
(defprotocol Foo
(bar [this])
(baz [this])
(deftype Qux [a b c]
Foo
(bar [this] a)
(baz [this] b))
(bar (Qux. 1 2 3))
(baz (Qux. 1 2 3))
I was looking for something like this(in pseudocode):
;; (1)
(`M-Tab` (Qux. 1 2 3))
;;
;; or (2):
(-> (Qux. 1 2 3) `M-Tab`)
to trigger a dropdown with bar & baz options.
As a workaround I'm currently using (2) but it needs to have at least 1st character to be present(autocomplete all options doesn't work).
Is there a better way to do it?
Thanks
For me auto-completion also works in case (1) when one character is present. It does not seem to specifically be aware of the functions belonging to the protocol, CIDER is just aware of the functions in scope. The completion-at-point does not seem to toggle without a first character. Maybe you can try asking on #cider of clojurians.slack.org?
šŸ˜„

how can I capture the expanded forms?

I'm trying to capture the expanded forms by defining my own module-begin:
(define-syntax-rule (my-module-begin e ...)
(#%module-begin
e ...
(foo e ...)))
Am I correct that foo here gets the original forms? If so is there a way for foo to get the expanded forms instead?
To get the expanded forms you'll need to use local-expand in some way.
Part 1, an incomplete solution
You might think to call local-expand separately on every expression like this:
#lang racket
(require syntax/parse/define
(for-syntax syntax/stx))
(define-simple-macro (my-module-begin e ...)
; define a function that expands it
#:do [(define (expand/mod-ctx e)
(local-expand e 'module '()))]
; get the expanded versions by calling that function on the e's
#:with (e-expanded ...) (stx-map expand/mod-ctx #'(e ...))
; use the expanded versions inside foo
(#%module-begin
e-expanded ...
(foo e-expanded ...)))
This works when the e forms are expressions like (+ 1 2) or (let ([x 3] [y 4]) (make-list x y)). However, it doesn't work when the e forms can be definitions.
Part 2, getting the expanded versions from Racket's #%module-begin
One way to support using local-expand with these module-level definitions is to wrap it in racket's #%module-begin form before expanding. This allows it to process all the es together in one call to local-expand.
(define-simple-macro (my-module-begin e ...)
; get the expanded versions by calling that function on a
; *constructed* module-begin form
#:with (_ e-expanded ...) (local-expand #'(#%module-begin e ...) 'module-begin '())
; use the expanded versions inside foo
(#%module-begin
e-expanded ...
(foo e-expanded ...)))
This gets Racket's #%module-begin to handle the definitions, and when it's done, you can pattern match on it with (_ e-expanded ...).

How to define symbols that will work like ( and ) by symbol macro?

I am trying define symbols a and b in following way
a + 1 1 b
2
I am trying to do this by using define-symbol-macro
(define-symbol-macro a '( )
(define-symbol-macro b ') )
but this way is not working.
What Lisp does with source code
Common Lisp is an incredibly flexible language, in part because its source code can be easily represented using the same data structures that are used in the language. The most common form of macro expansion transforms the these structures into other structures. These are the kind of macros that you can define with define-symbol-macro, define-compiler-macro, defmacro, and macrolet. Before any of those kind of macroexpansions can be performed, however, the system first needs to read the source from an input stream (typically a file, or an interactive prompt). That's the reader's responsibility. The reader also is capable of executing some special actions when it encounters certain characters, such ( and '. What you're trying to do probably needs to be happening down at the reader level, if you want to have, e.g., (read-from-string "a + 1 1 b") return the list (+ 1 1), which is what you want if you want (eval (read-from-string "a + 1 1 b")) to return 2. That said, you could also define a special custom language (like loop does) where a and b are treated specially.
Use set-macro-character, not define-symbol-macro
This isn't something that you would do using symbol-macros, but rather with macro characters. You can set macro characters using the aptly named set-macro-character. For instance, in the following, I set the macro character for % to be a function that reads a list, using read-delimited-list that should be terminated by ^. (Using the characters a and b here will prove very difficult, because you won't be able to write things like (set-macro-character ...) afterwards; it would be like writing (set-m(cro-ch(r(cter ...), which is not good.)
CL-USER> (set-macro-character #\% (lambda (stream ignore)
(declare (ignore ignore))
(read-delimited-list #\^ stream)))
T
CL-USER> % + 1 1 ^
2
The related set-syntax-from-char
There's a related function that almost does what you want here, set-syntax-from-char. You can use it to make one character behave like another. For instance, you can make % behave like (
CL-USER> (set-syntax-from-char #\% #\()
T
CL-USER> % + 1 1 )
2
However, since the macro character associated with ( isn't looking for a character that has the same syntax as ), but an actual ) character, you can't simply replace ) with ^ in the same way:
CL-USER> (set-syntax-from-char #\^ #\))
T
CL-USER> % + 1 1 ^
; Evaluation aborted on #<SB-INT:SIMPLE-READER-ERROR "unmatched close parenthesis" {1002C66031}>.
set-syntax-from-char is more useful when there's an existing character that, by itself does something that you want to imitate. For instance, if you wanted to make ! an additional quotation character:
CL-USER> (set-syntax-from-char #\! #\')
T
CL-USER> (list !a !(1 2 3))
(A (1 2 3))
or make % be a comment character, like it is in LaTeX:
CL-USER> (set-syntax-from-char #\% #\;)
T
CL-USER> (list 1 2 % 3 4
5 6)
(1 2 5 6)
But consider why you're doing this at allā€¦
Now, even though you can do all of this, it seems like something that would be utterly surprising to anyone who ran into it. (Perhaps you're entering an obfuscated coding competition? ;)) For the reasons shown above, doing this with commonly used characters such as a and b will also make it very difficult to write any more source code. It's probably a better bet to define an entirely new readtable that does what you want, or even write a new parser. even though (Common) Lisp lets you redefine the language, there are still things that it probably makes sense to leaveĀ alone.
A symbol-macro is a symbol that stands for another form. Seems like you want to look at reader macros.
http://clhs.lisp.se/Body/f_set__1.htm
http://dorophone.blogspot.no/2008/03/common-lisp-reader-macros-simple.html
I would second Rainer's comment though, what are you trying to make?
Ok so I love your comment on the reason for this and now I know this is for 'Just because it's lisp' then I am totally on board!
Ok so you are right about lisp being great to use to make new languages because we only have to 'compile' to valid lisp code and it will run. So while we cant use the normal compiler to do the transformation of the symbols 'a and 'b to brackets we can write this ourselves.
Ok so lets get started!
(defun symbol-name-equal (a b)
(and (symbolp a) (symbolp b) (equal (symbol-name a) (symbol-name b))))
(defun find-matching-weird (start-pos open-symbol close-symbol code)
(unless (symbol-name-equal open-symbol (nth start-pos code))
(error "start-pos does not point to a weird open-symbol"))
(let ((nest-index 0))
(loop :for item :in (nthcdr start-pos code)
:for i :from start-pos :do
(cond ((symbol-name-equal item open-symbol) (incf nest-index 1))
((symbol-name-equal item close-symbol) (incf nest-index -1)))
(when (eql nest-index 0)
(return i))
:finally (return nil))))
(defun weird-forms (open-symbol close-symbol body)
(cond ((null body) nil)
((listp body)
(let ((open-pos (position open-symbol body :test #'symbol-name-equal)))
(if open-pos
(let ((close-pos (find-matching-weird open-pos open-symbol close-symbol body)))
(if close-pos
(weird-forms open-symbol close-symbol
`(,#(subseq body 0 open-pos)
(,#(subseq body (1+ open-pos) close-pos))
,#(subseq body (1+ close-pos))))
(error "unmatched weird brackets")))
(if (find close-symbol body :test #'symbol-name-equal)
(error "unmatched weird brackets")
(loop for item in body collect
(weird-forms open-symbol close-symbol item))))))
(t body)))
(defmacro with-weird-forms ((open-symbol close-symbol) &body body)
`(progn
,#(weird-forms open-symbol close-symbol body)))
So there are a few parts to this.
First we have (symbol-name-equal), this is a helper function because we are now using symbols and symbols belong to packages. symbol-name-equal gives us a way of checking if the symbols have the same name ignoring what package they reside in.
Second we have (find-matching-weird). This is a function that takes a list and and index to an opening weird bracket and returns the index to the closing weird bracket. This makes sure we get the correct bracket even with nesting
Next we have (weird-forms). This is the juicy bit and what it does is to recursively walk through the list passed as the 'body' argument and do the following:
If body is an empty list just return it
if body is a list then
find the positions of our open and close symbols.
if only one of them is found then we have unmatched brackets.
if we find both symbols then make a new list with the bit between the start and end positions inside a nested list.
we then call weird forms on this result in case there are more weird-symbol-forms inside.
there are no weird symbols then just loop over the items in the list and call weird-form on them to keep the search going.
OK so that function transforms a list. For example try:
(weird-forms 'a 'b '(1 2 3 a 4 5 b 6 7))
But we want this to be proper lisp code that executes so we need to use a simple macro.
(with-weird-forms) is a macro that takes calls the weird-forms function and puts the result into our source code to be compiled by lisp. So if we have this:
(with-weird-forms (a b)
(+ 1 2 3 a - a + 1 2 3 b 10 5 b 11 23))
Then it macroexpands into:
(PROGN (+ 1 2 3 (- (+ 1 2 3) 10 5) 11 23))
Which is totally valid lisp code, so it will run!
CL-USER> (with-weird-forms (a b)
(+ 1 2 3 a - a + 1 2 3 b 10 5 b 11 23))
31
Finally if you have settled on the 'a' and 'b' brackets you could write another little macro:
(defmacro ab-lang (&rest code)
`(with-weird-forms (a b) ,#code))
Now try this:
(ab-lang a let* a a d 1 b a e a * d 5 b b b a format t "this stupid test gives: ~a" e b b)
Cheers mate, this was great fun to write. Sorry for dismissing the problem earlier on.
This kind of coding is very important as ultimately this is a tiny compiler for our weird language where symbols can be punctuation. Compilers are awesome and no language makes it as effortless to write them as lisp does.
Peace!

Lisp: Inspect function determine its required parameters

In Python, I can do this:
>>> def foo(x,y,z=1):
return x+y*z
>>> foo.func_code.co_varnames
('x', 'y', 'z')
>>> foo.func_defaults
(1,)
And from it, know how many parameters I must have in order to call foo(). How can I do this in Common Lisp?
Most implementations provide a way of doing this, but none is standardized. If you absolutely need it, Swank (the Common Lisp part of SLIME) has a function called swank-backend:arglist that, as far as I can see, does what you want:
CCL> (swank-backend:arglist 'if)
(TEST TRUE &OPTIONAL FALSE)
CCL> (swank-backend:arglist 'cons)
(X Y)
CCL> (swank-backend:arglist (lambda (a b c &rest args)))
(A B C &REST ARGS)
I'm not sure you can rely on it remaining available in the future, though.
Usually most Lisps have a function called ARGLIST in some package. LispWorks calls it FUNCTION-LAMBDA-LIST.
For information purposes in LispWorks, if one has the cursor on a function symbol, then control-shift-a displays the arglist. In LispWorks there is also an 'arglist-on-space' functionality that can be loaded. After typing a symbol and a space, the IDE displays the arglist.
There is also the CL:DESCRIBE function. It describes various objects. In most CL implementations it also should display the arglist of a function.
The following example is for Clozure Common Lisp:
Welcome to Clozure Common Lisp Version 1.6-r14468M (DarwinX8664)!
? (defun foo (x y &optional (z 1)) (+ x (* y z)))
FOO
? (arglist #'foo)
(X Y &OPTIONAL Z)
:ANALYSIS
? (describe #'foo)
#<Compiled-function FOO #x302000550F8F>
Name: FOO
Arglist (analysis): (X Y &OPTIONAL Z)
Bits: 8405508
...
If you want to know this just when editing, SLIME+emacs will take care of that for you.
e.g. In emacs lisp-mode + slime, typing
(format
will display the arguments of format in the minibuffer on the bottom.

How do I map a macro across a list in Scheme?

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?