Can Clojure generate function by macro? - macros

I'm trying to generator fn through macro.But I meet a strange issue.
Code is Here.
(defmacro test2 [lmk]
(fn [lmk2] (println lmk lmk2)))
((test2 12) 13) ;;----->Error
(defmacro test3 []
(fn [lmk] (println lmk)))
((test3) 12) ;;----->OK
(defmacro test4 []
`(fn [lmk] (println lmk)))
((test4) 12) ;;----->Error
I know defn can work well.I just want to know why I can't use defmacro here.And why test3 works well,however test2 fails.

In test2, prior to compilation, the test2 macro will be invoked (lmk has not yet been compiled or evaluated) - because there is no syntax quote, this will actually evaluate the fn form and return a function object (with lmk closed over). So you then have the form (fn-object 13) passed to the compiler, which I think is going down an unexpected path (not sure exactly what that is). Interestingly this works:
(def f (test2 12))
(f 13)
In test4, the syntax quote will cause each lmk symbol to be resolved in the namespace so that's the source of that error. You really want autogensyming on those:
(defmacro test4 []
`(fn [lmk#] (println lmk#)))

Related

Unbound variable error when using defmacro in LISP

I am trying to use macro with two forms in LISP, which evaluates both forms but always return the result of form 2. Below is the code that I am using -
(defmacro testmac (x body) (prog2 x body))
When executing the macro with following forms, It works correctly and always return 5 which is the second form.
(testmac (- 10 6) (/ 10 2))
However when I try to execute macro with following forms, its return error.
(testmac (print a) (print b))
Below is the error I get -
debugger invoked on a UNBOUND-VARIABLE: The variable B is unbound.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-INT:SIMPLE-EVAL-IN-LEXENV B #<NULL-LEXENV>)
Why am I getting this error and how can I use macro to make this work?
P.S. I cannot use defun need to use macro to execute (testmac (print a) (print b))
I am trying to use macro with two forms in LISP, which evaluates both forms but always return the result of form 2.
That's usually not a good idea - though it might be just not precise wording. A macro should not evaluate code - not without a good reason. Usually the macro just transforms code. The generated code then decides what to evaluate.
(defmacro testmac (x body) (prog2 x body))
(testmac (- 10 6) (/ 10 2))
So x is the list (- 10 6) and body is the list (/ 10 2).
Your macro returns the second list.
CL-USER 11 > (macroexpand-1 '(testmac (print a) (print b)))
(PRINT B)
The macro returns the form (print b). It then gets executed.
CL-USER 12 > (testmac (print a) (print b))
Error: The variable B is unbound.
If B is undefined you get the error you see.
There is no magic going on.
That's because your testmac macro directly executes (prog2 x body), instead of expanding into it.
You need to write it like this:
(defmacro testmac (x body)
`(prog2 ,x ,body))
The form after the backquote won't be evaluated, but those after a comma will.
You can (and you should!) test the expansion like this:
(macroexpand-1 '(testmac (print 42) (print 51)))
Which gives:
(PROG2 (PRINT 42) (PRINT 51))

unquote [& args] on macro

If I want to define a function that accepts an unknown number of args I can easily do something like this:
(defn foo
[& args]
args)
It returns a value of type clojure.lang.ArraySeq which contains the value given in the function.
In macro, using ~# is unquote-splicing, which flattens the argument given:
(defmacro foo
[bar & baz]
`(println ~#baz))
If I use the macro like this:
(foo "foo" 1 2 3 4)
It will print out 1 2 3 4. But, I want to get the args unflattened. Doing ~baz (without #) gives me an exception. Any idea how to do it?
If you macroexpand-1 the version using ~baz, the cause of the problem becomes apparent:
(macroexpand-1 '(foo "foo" 1 2 3 4)) ; NB. using ~baz in foo's body
;= (println (1 2 3 4))
; ^
So here we're attempting to call 1 as a function. (NB. this call takes place and the exception is thrown at run time.)
The right way to fix this depends on what you want to achieve. For example, you could pour the rest arg into a vector and print that:
(defmacro foo [bar & baz]
`(println ~(vec baz)))
A comment on MichaƂ Marczyk's answer ...
You can also see what's happening by turning the macro into a function:
(defn foo [bar & baz]
`(println ~#baz))
=> (foo "foo" 1 2 3 4)
(clojure.core/println (1 2 3 4))
Syntax quoting, unquoting, and unquote splicing still work. Aha! Macros differ from functions in how they are invoked, not in what they do.
You can always do
(defmacro foo
[bar & baz]
`(println (list ~#baz)))
to construct a seq or
(defmacro foo
[bar & baz]
`(println [~#baz]))
to construct a vector.

in clojure language what <'a> really is

actually i am trying to perfectly understand clojure and particularly symbols
(def a 1)
(type a)
;;=>java.lang.Long
(type 'a)
;;=>clojure.lang.Symbol
I know that type is a function so its arguments get evaluated first so i perfectly understand why the code above work this way .In the flowing code i decided to delay the evaluation using macro
(defmacro m-type [x] (type x))
(m-type a)
;;==>clojure.lang.Symbol
and i am fine with that but what i fail to uderstand is this:
(m-type 'a)
;;=>clojure.lang.Cons
why the type of 'a is a cons
the character ' is interpreted by the clojure reader as a reader-macro which expands to a list containing the symbol quote followed by whatever follows the ', so in your call to (m-type 'a) the 'a is expanding to:
user> (macroexpand-1 ''a)
(quote a)
then calling type on the list (quote a) which is a Cons.
This may be a bit more clear if we make the m-type macro print the arguments as it sees them while it is evaluating:
user> (defmacro m-type [x] (println "x is " x) (type x))
#'user/m-type
user> (m-type 'a)
x is (quote a)
clojure.lang.Cons

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

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}>