At a normal repl this works:
(defmacro evaluate
[to-eval]
(eval to-eval))
(evaluate +) ;=> #function[clojure.core/+]
However in clojurescript when using separate files like so:
file one: macro.clj
(ns space.macro)
(defmacro evaluate
[to-eval]
(eval to-eval))
file two: core.cljs
(ns space.core
(:require-macros [space.macro :refer [evaluate]))
(evaluate clojure.core/+) ;=> No error
(evaluate +) ;=> Unable to resolve symbol: + in this context
We get some errors. Which begs the question why? And how do you fix this?
This is because you need to have the symbol + get evaluated before it's handed to the macro so that the symbol is resolved before it's handed to the other namespace. You can do that with quoting like so:
(defmacro evaluate
[to-eval]
`(eval ~to-eval))
Check out the chapter on macros in "Clojure For the Brave and True" for a better explanation: http://www.braveclojure.com/writing-macros/#Simple_Quoting
Related
How do you find all the free variables in a Clojure expression?
By free variables, I mean all the symbols that are not defined in the local environment (including all local environments defined inside the expression), not defined in the global environment (all symbols in the current namespace, including all those imported from other namespaces), and not a Clojure primitive.
For example, there is one free variable in this expression:
(fn [ub]
(* (rand-int ub) scaling-factor))
and that is scaling-factor. fn, *, and rand-int are all defined in the global environment. ub is defined in the scope that it occurs within, so it's a bound variable, too (i.e. not free).
I suppose I could write this myself—it doesn't look too hard—but I'm hoping that there's some standard way to do it that I should use, or a standard way to access the Clojure compiler to do this (since the Clojure compiler surely has to do this, too). One potential pitfall for a naïve implementation is that all macros within the expression must be fully expanded, since macros can introduce new free variables.
You can analyze the form with tools.analyzer.jvm passing the specific callback to handle symbols that cannot be resolved.
Something like this:
(require '[clojure.tools.analyzer.jvm :as ana.jvm])
(def free-variables (atom #{}))
(defn save-and-replace-with-nil [_ s _]
(swap! free-variables conj s)
;; replacing unresolved symbol with `nil`
;; in order to keep AST valid
{:op :const
:env {}
:type :nil
:literal? true
:val nil
:form nil
:top-level true
:o-tag nil
:tag nil})
(ana.jvm/analyze
'(fn [ub]
(* (rand-int ub) scaling-factor))
(ana.jvm/empty-env)
{:passes-opts
(assoc ana.jvm/default-passes-opts
:validate/unresolvable-symbol-handler save-and-replace-with-nil)})
(println #free-variables) ;; => #{scaling-factor}
It will also handle macroexpansion correctly:
(defmacro produce-free-var []
`(do unresolved))
(ana.jvm/analyze
'(let [x :foo] (produce-free-var))
(ana.jvm/empty-env)
{:passes-opts
(assoc ana.jvm/default-passes-opts
:validate/unresolvable-symbol-handler save-and-replace-with-nil)})
(println #free-variables) ;; => #{scaling-factor unresolved}
I am attempting to learn Clojure and am having trouble with macros. I have a simple macro:
(defmacro add [& x] `(apply + (list ~#x)))
and then I have a function that can call multiple operations (add, subtract, multiply, and divide). I get these from stdin but for simplicity I have created a variable holding a list of numbers:
(defn do-op
[op]
(def numbers (list 1 2 3))
(apply op numbers))
In order to call do-op with the appropriate operation I need to pass the macro to do-op in an anonymous function:
(do-op #(add %&))
When I run this code using arguments passed from stdin I get a confusing error:
Cannot cast clojure.lang.ChunkedCons to java.lang.Number
When I execute this in a REPL I get:
Cannot cast clojure.lang.PersistentList to java.lang.Number
I assume that this has something to do with my lack of understanding of how these variadic arguments are getting handled but I am thoroughly stumped. What am I missing?
You can never ever pass a macro as if it was a function, since it doesn't exist after the code is compiled and ready to run.
When you have;
(do-op #(add %&)) ; which is shorthand for
(do-op (fn [& rest] (add rest))) ; then you expand the macro
(do-op (fn [& rest] (apply + (list (UNQUOTE-SPLICE 'rest)))) ; how do you unsplice the symbol rest to be separate elements?
The short answer is that rest can never be unspliced and thus you are using the macro wrong. However it seems you are just making an alias for + and it can be done by making a function or just making a binding to the original:
(defn add [& args] (apply + args)) ; making a function that calls + with its arguments
(def add +) ; or just make a binding pointing to the same function as + points to
(do-op add) ; ==> 6
You should keep to using functions as abstraction. Whenever you need to write something very verbose, where you cannot make it a function because of too early evaluation, then you have a candidate for a macro. It then translates a shorter way to write it with the long verbose way to write it without knowing the actual data types behind the variable symbols, since the compiler won't know what they are when expanding the macro. Also a macro gets expanded once, while the function that had the macro might get executed many times.
EDIT
In your pastebin code I can confirm you never ever need a macro:
(cond
(= 1 option) (do-op #(add %&))
...)
Should just be
(cond
(= 1 option) (do-op +)
...)
No need to wrap or make macro for this. Pass the function as is and it will do what you want.
Macros run at compile time and transform code data, not runtime data.
There is simply no way to generically apply to a macro a form evaluating to a sequence (like the symbol numbers) because it needs be to evaluated first, which can only happen at runtime (after compile time).
This is the full answer. Hopefully it helps you along understanding macros in Clojure.
If I understand what you are thinking, you should do it more like this:
(ns clj.core
(:require
[tupelo.core :as t]
))
(t/refer-tupelo)
(defn add [& x]
(apply + x))
(def numbers [1 2 3] )
(defn do-op
[op]
(apply op numbers))
(spyx (do-op add))
(defn do-op-2
[op vals]
(apply op vals))
(spyx (do-op-2 add numbers))
to get result:
> lein run
(do-op add) => 6
(do-op-2 add numbers) => 6
Usually we try to avoid having functions access global values like numbers. With do-op-2 we pass the vector of numbers into the function instead.
Note: For (spyx ...) to work you're project.clj must include
:dependencies [
[tupelo "0.9.9"]
Update
Of course, you don't really need do-op, you could do:
(defn add-all [nums-vec]
(apply + nums-vec))
(spyx (add-all numbers))
;=> (add-all numbers) => 6
I'm doing my first steps with Clojure today and I encountered the first confusing obstacle right off the bat!
I've built a new Leiningen(2.5.1) project and just want to run the default code, which is:
(ns wavescript.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
Problem is the Lighttable(0.7.2) console tells:
WARNING: unsigned-bit-shift-right already refers to:
#'clojure.core/unsigned-bit-shift-right in namespace: cljs.core,
being replaced by: #'cljs.core/unsigned-bit-shift-right
I found some Google entries but none brought me further. What this is about?
This is caused by the symbol unsigned-bit-shift-right being found in the clojure.core namespace as well as a cljs.core. The clojure.core namespace is compiled/loaded before cljs.core, and the introduction of the new symbol is throwing the warning. It looks like, from the namespace, you are writing clojurescript. If you look at this file cljs.core on line 2147, you will see this form:
(defn unsigned-bit-shift-right
"Bitwise shift right with zero fill"
[x n] (cljs.core/unsigned-bit-shift-right x n))
in the cljs.core namespace. So, apparently, lighttable is importing both clojure.core and clj.core.
Honestly, I am not even sure how the cljs implementation is working, as it is completely self-referential. Additionally, there are uses of unsigned-bit-shift-right starting at line 451 that are not prefixed, so they must be using the clojure.core implementation. Bizarre. The above form appears after all the previous uses. It looks safe to say that symbol can be safely excluded. In fact, this may deserve a patch...
To resolve this, you might want to try to explicitly state your namespace importations and exclude that import. The refer function affords that.
So, you would have a namespace that looks like this
(ns my.namespace.hello-world
[:require
[cljs.core :exclude [unsigned-bit-shift-right]]])
The clojure.core implementation looks like this:
(defn unsigned-bit-shift-right
"Bitwise shift right, without sign-extension."
{:inline (fn [x n] `(. clojure.lang.Numbers (unsignedShiftRight ~x ~n)))
:added "1.6"}
[x n] (. clojure.lang.Numbers unsignedShiftRight x n))
Alternately, since they are wrapping the functionality, perhaps cljs.core is designed to not need to expose clojure.core. If that is the case, then exclude clojure.core, and see if you code will function properly.
In fact, from looking at the cljs.core namespace:
(ns cljs.core
(:refer-clojure :exclude [-> ->> .. amap and areduce alength aclone assert binding bound-fn case comment cond condp
declare definline definterface defmethod defmulti defn defn- defonce
defprotocol defrecord defstruct deftype delay destructure doseq dosync dotimes doto
extend-protocol extend-type fn for future gen-class gen-interface
if-let if-not import io! lazy-cat lazy-seq let letfn locking loop
memfn ns or proxy proxy-super pvalues refer-clojure reify sync time
when when-first when-let when-not while with-bindings with-in-str
with-loading-context with-local-vars with-open with-out-str with-precision with-redefs
satisfies? identical? true? false? number? nil? instance? symbol? keyword? string? str get
make-array vector list hash-map array-map hash-set
aget aset
+ - * / < <= > >= == zero? pos? neg? inc dec max min mod
byte char short int long float double
unchecked-byte unchecked-char unchecked-short unchecked-int
unchecked-long unchecked-float unchecked-double
unchecked-add unchecked-add-int unchecked-dec unchecked-dec-int
unchecked-divide unchecked-divide-int unchecked-inc unchecked-inc-int
unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int
unchecked-subtract unchecked-subtract-int unchecked-remainder-int
unsigned-bit-shift-right
bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set
bit-test bit-shift-left bit-shift-right bit-xor
cond-> cond->> as-> some-> some->>
if-some when-some test ns-interns var vswap!])
You can see that unsigned-bit-shift-right is supposed to be excluded from the namespace. So, you will want to exclude clojure.core to resolve the problem.
In Clojure, you need to use gensym to create symbols for internal use in your macros to keep them hygienic. However, sometimes you need to use the same symbol in nested syntax-quotes. For example, if I want to bind a value to a symbol with let and print it three times in an unrolled loop, I'd do
`(let [x# 1]
~#(repeat 3
`(println x#)))
But that would produce
(clojure.core/let [x__2__auto__ 1]
(clojure.core/println x__1__auto__)
(clojure.core/println x__1__auto__)
(clojure.core/println x__1__auto__))
x# generates a different symbol in the let form than in the println forms nested within it - because they were created from different syntax-quotes.
To solve it, I can generate the symbol beforehand and inject it to the syntax-quotes:
(let [x (gensym)]
`(let [~x 1]
~#(repeat 3
`(println ~x)))
)
This will produce the correct result, with the same symbol everywhere needed:
(clojure.core/let [G__7 1]
(clojure.core/println G__7)
(clojure.core/println G__7)
(clojure.core/println G__7))
Now, while it does produce the right result, the code itself looks ugly and verbose. I don't like having to "declare" a symbol, and the injection syntax makes it look like it came from outside the macro, or calculated somewhere within in it. I want to be able to use the auto-gensym syntax, which makes it clear that those are macro-internal symbols.
So, is there any way to use auto-gensym with nested syntax-quotes and make them produce the same symbol?
Auto-gensym'd symbols are only valid within the syntax-quote that defines them and they don't work in unquoted code because that is not part of the syntax quote.
Here the symbol x# gets replaced by it's gensym because it is within the scope of the syntax quote:
core> `(let [x# 1] x#)
(clojure.core/let [x__1942__auto__ 1] x__1942__auto__)
And if you unquote it it no longer gets translated into it's syntax quote:
core> `(let [x# 1] ~#x#)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x# in this context, compiling:(NO_SOURCE_PATH:1)
Auto-gensyms are a very convenient shortcut within the syntax-quote, everywhere else you apparently need to use gensym directly as is the case with your later example.
there are other ways to structure this macro so autogensyms will work though declaring gensymed symbols in a let at the top of a macro is very normal in Clojure and other lisps as well.
Your method (calling gensym) is the right one.
However in some cases you can get by with a clever use of doto, -> or ->>. See:
`(let [x# 1]
(doto x#
~#(repeat 3 `println)))
More generally you can do the following whenever faced with this situation:
(let [x `x#]
`(let [~x 1]
~#(repeat 3
`(println ~x))))
To be clear, you create the auto-gensym and bind it outside of the syntax-quoted form, and then inside any nested forms which require it you can just use syntax-unquote.
I believe I understand that during macro expansion, a macro does not have access to the things a function has access to, because expansion happens before compile time.
But, I am having trouble understanding is how to perform checks at macro expansion time.
For example:
(defn gen-class [cl-nam]
(fn [cmd & args]
(condp = cmd
:name (name cl-nam))))
(defmacro defnclass [cl-nam]
`(def ~cl-nam (gen-class '~cl-nam)))
I would like to check to see that cl-nam is not a sequence. I would like to use count and find out of its length is > 1.
I understand I can unquote the println in the following macro, so that I can get an expansion-time message.
(defmacro defnclass_info [cl-nam]
`(do
~(println cl-nam)
(def ~cl-nam (gen-class '~cl-nam))))
But, I am not sure how to go about checking to see what was passed for cl-nam.
I'm reading a lot of Clojure macro descriptions from several books, and am stumped.
Thanks.
A macro is really just a function.
(defmacro defnclass-info
[cl-name]
(when (seq? cl-name)
(throw (Exception. "cl-name must not be a sequence")))
`(def ~cl-name (gen-class '~cl-name)))
Edit: One could also switch behaviour and recursively call the macro again for the whole list. What you do, depends on your requirements.
(defmacro defnclass-info
[cl-name]
(if (seq? cl-name)
`(do ~#(for [cn cl-name] `(defnclass-info ~cn)))
`(def ~cl-name (gen-class '~cl-name))))
The macro expansion is just what the "function" returns. So you have full flexibility on what you do with the macro arguments.