Scheme: Passing defines inside macro definition to submacro? - macros

Consider the following macro definition in R7RS scheme:
(define-syntax foo
(syntax-rules ()
((_ bar)
(begin
(define baz 42)
(define-syntax bar
(syntax-rules ()
((_) baz)))))))
I have loaded this file into the repl of chibi-scheme and entered:
> (foo bar)
> (bar)
Instead of the expected output 42, I got:
ERROR: undefined variable: baz
Why is this so and how can I pass the defined value of baz in the outer macro to the inner macro?

This is an error in chibi-scheme. A macro definition needs to capture its environment; for bar the environment consists of bar itself and baz. Then when you expand bar in another environment, the macro expansion needs to recognize that baz is bound in the env-of-definition. chibi-scheme apparently doesn't recognize that baz is actually defined.
Additionally, another related problem, which you haven't seen in your post, is that even if the expansion of bar recognizes baz as bound, the loading/running of the code needs to find the value of baz.
Here is R6RS Ikarus Scheme:
> (define-syntax foo
(syntax-rules ()
((_ bar)
(begin
(define baz 42)
(define-syntax bar
(syntax-rules ()
((_) baz)))))))
> (foo bar)
> (bar)
42
>

I've run this on all the Schemes in my test suite that support syntax-rules, and it fails only on Chibi and MIT. I don't see any reason why it shouldn't work, but I confess that macrology is still something of a black art to me. In particular, it works in Foment, which is an R7RS system. I haven't been able to build Sagittarius, so I can't test it there.

Related

Scheme macros with 2 params

Can I define macro that will get one param from left and one from right part of macro? I want to write some kind of this in my programs:
(test = 10)
to define new variables
I tried to write that macro:
(define-syntax =
(syntax-rules ()
((a _ b)
(define a b))))
But I've got error "bad syntax in: ="
Since the form is determined by the first element you'd have problems with test not being bound.
The right way is this:
(= test 10)
You write the macro like this:
(define-syntax =
(syntax-rules ()
((_ a b) (define a b))))
There you go. Without horrible infix syntax.

SBCL forward declaration: possible?

I'm writing some code in SBCL, and the ordering of my functions keeps causing warnings of the following type to appear when I load files into the REPL:
;caught STYLE-WARNING:
undefined function: FOO
Where FOO is the symbol for the function. This is purely due to how they are ordered in my file, as the function FOO is defined, just not before the part of the code that throws that warning.
Now, in Clojure, which is the Lisp I'm familiar with, I have the declare form, which lets me make forward declarations to avoid this kind of issue. Is there something similar for SBCL/Common Lisp in general?
We can use the '(declaim (ftype ...))' for that:
(declaim (ftype (function (integer list) t) ith))
(defun foo (xs)
(ith 0 xs))
(defun ith (n xs)
(nth n xs))
Both the function 'foo' and 'ith' works fine and there is not any style warning about that.
http://www.lispworks.com/documentation/HyperSpec/Body/d_ftype.htm
Here's what I found in the manual, section 4.1.1:
CL-USER> (defun foo (x) (bar x))
; in: DEFUN FOO
; (BAR X)
;
; caught STYLE-WARNING:
; undefined function: BAR
;
; compilation unit finished
; Undefined function:
; BAR
; caught 1 STYLE-WARNING condition
FOO
CL-USER> (declaim (sb-ext:muffle-conditions style-warning))
; No value
CL-USER> (defun baz (y) (quux y))
BAZ
So you can at least silence the style warnings.
I also thought about how SBCL is handling the evaluation step in the REPL: it compiles the code. So I restarted the inferior lisp process and ran "compile region" on the following two lines:
(defun foo (x) (bar x))
(defun bar (y) (baz y))
and SBCL only complained about baz, but not about bar. Are you giving single functions to SBCL or larger chunks?

Reverting to global scope in macro in clojure?

I want to make a macro which defines a function outside of the local variable scope, as to catch errors where the programmer (aka me) is incorrectly referencing variables in the local scope. It should only allow variables declared in the first argument of the macro.
For example, the following should compile fine:
(let [ foo 'x
bar 'y ]
(my-macro [ foo ] ;; this designates that foo can be used
(print foo)
)
)
but, the following should fail to compile, because "bar" wasn't declared in the first argument of my-macro:
(let [ foo 'x
bar 'y ]
(my-macro [ foo ] ;; only foo is declared here, but bar
;; is used, so should fail to compile
(print foo)
(print bar) ;; <-- should fail here
)
)
Besides the error checking, the macro needs to return a vector of the values of the variables used and a function containing the body. This is what I have so far.
(defmacro my-macro
[ declared-vars-in-use & body ]
`[~declared-vars-in-use (fn [~#declared-vars-in-use]
~#body
)
]
)
The only thing I don't know how to do is enforce the compilation error when referencing a symbol from the local scope that isn't declared in my-macro ("bar" in the above example). Forgive me if I'm using incorrect terms, and hopefully you can understand this, I am still a newbie at clojure.
(Updated with a version of explicit-closure free from the considerable limitations of the original approach.)
The macro below returns a function which closes over the specified locals and accepts specified additional arguments. If you only want a function which doesn't close over any locals at all (in other words, whose body only uses no external locals), which is what my-macro would produce if given the desired ability to prevent access to locals not on the declared-vars-in-use list (as the locals on the list would be shadowed by the parameters), you can simply eval an appropriate fn form, as eval ignores locals. (So, skip close-over and the let around the inner list* in the snippet below.)
(defmacro explicit-closure [close-over params & body]
(eval (list 'let
(vec (interleave close-over (repeat nil)))
(list* 'fn params body)))
`[~close-over (fn [~#params] ~#body)])
Note that the call to eval here happens during compilation and is only meant to coax the compiler into complaining if the function body references the wrong locals. If the body does not use disallowed locals or otherwise cause the eval call to fail, regular code for the function is emitted with no further checks or eval-induced compilation at runtime.
From the REPL:
(let [foo 1
bar 2]
(explicit-closure [foo] [x] (+ foo x)))
;= [[1] #<user$eval1887$fn__1888 user$eval1887$fn__1888#39c4d0cd>]
(let [foo 1
bar 2]
(let [[vals f] (explicit-closure [foo] [x] (+ foo x))]
(prn vals)
(f 3)))
;=> [1]
;= 4
;;; replace (+ foo x) with (+ foo bar x) in the above
;;; to get a CompilerException

Why doesn't Dr. Racket expand nested 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.

Can I make a clojure macro that will allow me to get a list of all functions created by the macro?

I would like to have a macro which I'll call def-foo. Def-foo will create a function, and then will add this function to a set.
So I could call
(def-foo bar ...)
(def-foo baz ...)
And then there would be some set, e.g. all-foos, which I could call:
all-foos
=> #{bar, baz}
Essentially, I'm just trying to avoid repeating myself. I could of course define the functions in the normal way, (defn bar ...) and then write the set manually.
A better alternative, and simpler than the macro idea, would be to do:
(def foos #{(defn bar ...) (defn baz ...)} )
But I'm still curious as to whether there is a good way for the macro idea to work.
Do you want to end up with a set that has the names of functions in it (i.e. a set of Symbols), or a set containing vars (which resolve to functions)? If you want the former, you can add the symbols to an atom in the macro at compile-time, like Greg Harman's version.
If you want the latter, your macro must expand to code that does the atom-swapping after the function is defined. Remember that macros run at compile-time and the macro-expanded result runs at run-time; the function itself is not available until run-time.
(def all-foos (atom #{}))
(defmacro def-foo [x]
`(let [var# (defn ~x [] (println "I am" '~x))]
(swap! all-foos conj var#)))
If you want to be able to call the functions in this set, for example, you need to use the latter version.
user> (def-foo foo)
#{#'user/foo}
user> (def-foo bar)
#{#'user/foo #'user/bar}
user> ((first #all-foos))
I am foo
nil
Have the macro add the name of the new function to your set before creating the function, like so:
(def *foos* (atom (hash-set)))
(defmacro def-foo [name]
(swap! *foos* conj name)
`(defn ~name
[]
(println "This is a foo!")))
Result:
user=> (def-foo bar)
#'user/bar
user=> (def-foo baz)
#'user/baz
user=> (bar)
This is a foo!
nil
user=> (baz)
This is a foo!
nil
user=> *foos*
#<Atom#186b11c: #{baz bar}>