I am trying to write a macro that, given a form, defines all missing symbols as themselve.
By now I have the following:
(def ^:private missing-symbol-pattern #"Unable to resolve symbol: (.+) in this context")
(cl/defn ^:private missing-symbol [s]
(cl/when-let [[_ sym] (cl/re-find missing-symbol-pattern s)] sym))
(cl/defmacro try-eval [expr]
`(try (do (cl/println '~expr) (cl/eval '~expr))
(catch Exception e#
(cl/if-let [sym# (do (cl/println (.getMessage e#)) (missing-symbol (.getMessage e#)))]
(cl/eval `(do
(def ~(cl/symbol sym#) '~(cl/symbol sym#))
(cl/println ~sym#)
(try-eval ~'~expr)))
(cl/eval `(throw ~e#))))))
(cl here is an alias for clojure.core)
I know that there can be problems with side-effects, but this is not important here (although a solution without side-effect problems would be better)
If there is more than one missing (unresolvable) symbol, I get the following Exception:
java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined: java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to clojure.lang.IDeref, compiling:(shen/primitives.clj:517)
Has anyone an idea on what to change? Is there some "ready made" solution?
Cheers
Rather than using try/catch to find symbols that won't resolve, maybe you could do something using &env symbol available inside of defmacro. The keys of &env are the locally defined symbols.
(Article about &env and &form.)
Using a combination of resolve and (keys &env) you can isolate the symbols that aren't defined, then you can choose to def the ones that are (not (or (resolve sym) (contains? &env sym))
We do something akin to this in the Midje source code, to determine which symbols in a tabular test are already defined and which ones aren't:
[Note: in the below code locals is in fact (keys &env)]
(defn- headings-rows+values [table locals]
(letfn [(table-variable? [s]
(and (symbol? s)
(not (metaconstant-symbol? s))
(not (resolve s))
(not (contains? locals s))))]
(split-with table-variable? (remove-pipes+where table))))
Related
I get this error:
Error: Class named ENTITY not found.
While executing: FIND-CLASS, in process Listener(4).
Type cmd-/ to continue, cmd-. to abort, cmd-\ for a list of available restarts.
If continued: Try finding the class again
Type :? for other options.
When I load/compile a file with this macro in it:
(defmacro def-post-entity (entity)
(let* ((repository-var-name (cl-ddd::repository-var entity))
(base-url (string-downcase (concatenate 'string "/api/" (string entity))))
(progn-statement '(progn)))
(loop
for slot in (ccl:class-slots (find-class entity))
append `(setf (,(ccl:slot-definition-name slot) new-entity)
(cdr (assoc ,(string (ccl:slot-definition-name slot)) params :test #'string=)))
into progn-statement)
`(setf (ningle:route cl::*app* ,base-url :method :post)
(lambda (params)
(let ((new-entity (make-instance ,entity)))
(,progn-statement))))))
As I understand lisp macros (I'm new), there's no reason for find-class to expect entity to be a classname, it's a parameter to the macro. The error message indicates that find-class is being executed, but it's not. I'm just loading the file containing this macro via (ql:quickload "filename") or compile it directly.
Any help would be appreciated in helping me to understand what's happening, and to fix it.
The problem was the macro AFTer this one, where I call def-post-entity. It's a macro as well, and I forgot that that would mean def-post-entity gets expanded there as well.
Coredumps comment helped me figure it out.
I am new to Clojure and I am having trouble understanding its quoting system. I am writing a macro and I have made two similar cases - one works, the other doesn't. In a sense, I am just trying to surround my statement with try/catch condition.
Here's the code that works:
(defmacro safe
[arg1 arg2]
(list 'let arg1 arg2)
)
Here's the code that doesn't work
(defmacro safe
[arg1 arg2]
'(try
~(list 'let arg1 arg2)
(catch Exception e (str "Error: " (.getMessage e)))
)
)
after the ~ symbol, it should escape the quotes, but for some reason, it seems like it doesn't. The Error is: "Unable to resolve symbol: arg1 in this context...".
Thanks for your help!
Edit:
Code that I call the macro with:
(println (safe [s (new FileReader (new File "text.txt"))] (.read s)))
Also, I import this:
(import java.io.FileReader java.io.File)
Goal is to read first symbol from a file, while being safe from incorrect text file names. This is my school assignment by the way, so I should not use any other way to do it and the macro has to be called like that, I know about the with-open, etc.
Escaping (~) only works with quasi-quote (also known as syntax quote). You need to use the "back-quote" (`, found on the same key as ~ on most US keyboards), not the normal single-quote (', which is on the same key as "). It's a subtle difference graphically, which can be easy to miss.
You can also get rid of the list by not quoting the let and un-quoting arg1 and arg2. With these changes, we get something like this:
`(try ;; note back-quote, not regular quote.
(let ~arg1 ~arg2) ;; Getting rid of list — not necessary, but most find this more readable
(catch Exception e (str "Error: " (.getMessage e))))
Now, if we check our progress using macroexpand:
(macroexpand '(safe2 [s (new FileReader (new File "text.txt"))] (.read s)))
We get the following:
(try (clojure.core/let [s (new FileReader (new File text.txt))]
(.read s))
(catch java.lang.Exception user/e
(clojure.core/str Error: (.getMessage user/e))))
You might notice that in Clojure, quasi-quoted symbols are resolved when the macro is compiled. Symbols that can't be resolved are qualified with the current namespace (user in this case). The rationale for this is that it helps you write "hygienic" macros. In this case, however, we don't want to resolve the e symbol, because local variables can't be given a qualified name.
We have a few options now. The first is to basically forgo hygiene. That works in this case, since you aren't expanding any user-provided code inside the catch block. So there isn't any way the name e could conflict with a user variable. This solution would look like this:
`(try
(let ~arg1 ~arg2)
(catch Exception ~'e (str "Error: " (.getMessage ~'e))))
Note the use of ~'e instead of just e. The ~ is to escape from the quasi-quote, then we use a regular quote to quote e. It looks a little weird, but it works.
While the above solution works, it's arguably better to use a generated symbol instead of e. That way, if you ever change your macro to accept user-provided code for the catch block, you can be sure it will still work. In this particular case, an "auto-generated" symbol fits the bill perfectly. This looks as follows:
`(try
(let ~arg1 ~arg2)
(catch Exception e# (str "Error: " (.getMessage e#))))
Basically, whenever the Clojure reader encounters a symbol with a trailing # inside a quasi-quote form, it will produce a new gensym'd symbol and replace every occurence of that symbol (i.e., e#) with the gensym'd one. If we macroexpand this, we would get something like:
(try (clojure.core/let [s (new FileReader (new File text.txt))]
(.read s))
(catch java.lang.Exception e__66__auto__
(clojure.core/str Error: (.getMessage e__66__auto__))))
As you can see, every occurence of e# was replaced with a machine-generated symbol. Here e__66__auto__ is the auto-gen'd symbol.
Finally, while auto-gen is convenient, it is not always sufficient. The main issue is that, since auto-gen'd symbols are produced at read time, every evaluation of the quasi-quote form (i.e., expansion of the macro) will use the same auto-gen'd symbols. In this paricular case, that's fine. However, there are cases where this can lead to conflicts if, for example, nested macro forms are used. In these cases, it is necessary to use an explicitly gensym'd symbol every time the macro is expanded. With this approach, the body of your macro would look like this:
(let [e (gensym)]
`(try
(let ~arg1 ~arg2)
(catch Exception ~e (str "Error: " (.getMessage ~e)))))
Here e is a local variable in your macro, whose value is the a fresh symbol (via gensym). In the quasi-quote, we must escape e in order to use that gensym'd value.
If we expand this, we would get something like:
(try (clojure.core/let [s (new FileReader (new File text.txt))]
(.read s))
(catch java.lang.Exception G__771
(clojure.core/str Error: (.getMessage G__771))))
If we expand this again, we would find G__771 replaced by a different symbol (perhaps G__774). In contrast, the auto-gen'd solution (e#) would always use the same symbol for every expansion (at least until we recompile the macro).
Hopefully this gives you a better understanding of macros, symbols, and hygiene. Let me know if anything isn't clear.
There’s two problems here:
First, unsplicing (~ and ~#) work only inside syntax-quote (`). Syntax quote is usually chosen for macros because it also does symbol namespace resolution at macro definition place. Simple quote (') will keep symbols intact, so ns resolution will happen at macro invocation site. Because you do not control where and how your macro will be called, it might be very confusing.
Second, you cannot just declare new symbols in quoted code, it may cause name conflict with code around macro. Each new symbol introduced by macro should use suffix # so Clojure macroexpansion will replace it with new autogenerated name that cannot cause any name conflicts with user code.
(defmacro m []
`(let [x# 1]
x#))
(macroexpand-1 '(m)) =>
=> (clojure.core/let [x__6257__auto__ 1]
x__6257__auto__)
Note how let became fully-qualified clojure.core/let (avoiding ns resolution nuances later), and x# got replaced with x__6257__auto__ (avoiding name conflicts).
Your code should be written as this:
(defmacro safe [arg1 arg2]
`(try
(let ~arg1 ~arg2)
(catch Exception e#
(str "Error: " (.getMessage e#)))))
Check like this:
(macroexpand-1 '(safe [s (new FileReader (new File "text.txt"))] (.read s)))
↓↓↓
(try
(clojure.core/let [s (new FileReader (new File "text.txt"))]
(.read s))
(catch java.lang.Exception e__6283__auto__
(clojure.core/str "Error: " (.getMessage e__6283__auto__))))
I would also recommend using idiomatic names for macro args and make second argument of arbitrary length:
(defmacro safe-let [bindings & body]
`(try
(let ~bindings
~#body)
(catch Exception e#
(str "Error: " (.getMessage e#)))))
I am trying to define a macro like this:
(defmacro foo-macro
"[name] is the name of the function to define
[meta-data] is the map that defines the meta-data of the function"
[name meta-data]
(let [vals (gensym "label-")]
`(def ~name
^#~meta-data
(fn [~vals] (eval nil)))))
However, I am getting this compilation error:
Unhandled java.lang.IllegalArgumentException Metadata must be
Symbol,Keyword,String or Map
I think this is normal. However, I am not sure how I can make such a macro to work, or if it is even possible.
Note: I do not want to use with-meta. Read the revision of the resolution of this other question to understand why: Clojure: issues getting the symbol of a function in a looping context.
The only reason why I would use with-meta, is if you have a way to make it return a non-AFunc identifier.
I'm sorry, but you do want to use with-meta, you just want to use it within your macro rather than within the code you return.
The form that you get by reading ^{:foo :bar} (fn []) is approximately the same as what you get by evaluating (with-meta `(fn [])), so that's what you want to do in your macro: evaluate the with-meta call while generating code.
(defmacro foo-macro
"[name] is the name of the function to define
[meta-data] is the map that defines the meta-data of the function"
[name meta-data]
(let [vals (gensym "label-")]
`(def ~name
~(with-meta `(fn [~vals] (eval nil))
meta-data))))
Calling (foo-macro fn-name {:foo "bar"}) should give you what you want: a function with (meta fn-name) returning {:foo "bar"} which, when printed, comes out something like #<user$fn_name user$fn_name#35df85a1>.
UPDATE:
Thanks for all the help so far. This is my new code, which works. But not exactly as I would like it to.
I need it to return the java exception (don't ask me why).
Example:
(safe (/ 1 0))
#<ArithmeticException java.lang.ArithmeticException: Divide by zero>
which is how I want it to be. But when I make use of the other clauses of code that handle bindings etc, I get the Clojure exception:
(seefe [f(FileReader.(File. "C:/txtf.txt"))](. f read))
FileNotFoundException C:\txtf.txt (The system cannot find the file specified) java.io.FileInputStream.open (:-2)
What can I do to prevent this, and show the Java exception instead?
(defmacro safe [bindings & code]
(if (list? bindings)
`(try
(println "line 8: try")
~bindings
(catch Throwable e# e#))
(if (= (count bindings) 0)
`(try ~code
(catch Throwable e# e#))
`(let ~(subvec bindings 0 2)
(try
(safe ~(subvec bindings 2) ~#code)
(catch Throwable e# e#)
(finally
(. ~(bindings 0) close)))))))
OLD
I'm trying to get an assignment done, but it's impossible without any tutoring. My teachers expect us to teach ourselves Clojure in 1 week and complete this assignment. Everyone in my class is stuck and we already hate the teacher, lmao.
Okay, so the macro is supposed to be able to try code, and return a result or an exception. It's supposed to be able to handle expressions like:
(def v (safe [s (FileReader. (File. "file.txt"))] (. s read)))
If the code opened any filestreams or whatnot, it should close them in a finally clause.
This is what I got so far - I realize it's not working.
(defmacro safe [& body]
`(try ~#body
(catch Throwable e# e#)
(finally
(if (. ~#body isInstance Closable) (. ~#body close)))))
The error I get is:
Unable to resolve symbol: s in this context,
compiling:(NO_SOURCE_PATH:1)
I got desperate so I tried alot of different stuff, I tried:
to edit the macro:
(defmacro safe [& body]
`(try ~#body
(catch Throwable e# e#)
(finally (if (. ~#body isInstance Closable) (. ~#body close)))))
then run:
(safe (. (java.io.FileReader. (java.io.File. "C:/Users/Dyallo.L/Dropbox/DVK11/PROP/Clojure/txt.txt")) read))
Which resulted in:
No such var: clooj.cemerick.pomegranate/Closable,
compiling:(NO_SOURCE_PATH:1)
Someone mentioned the macro WITH-OPEN but I guess that won't work well with my generic macro. The macro isn't meant for opening files, but if they are, it should definately close them.
So darn, won't you give me a hand Stackoverflow-geniuses?
Thanks in beforehand.
from the example it looks like the first form passed to the safe macro is a vector of name expression pairs [a (open-something "/foo/bar") b (oopen-something-else)] followed be some number of expressions that use these symbols. if I'm interpreting the assignment correctly the result would be quite similar to with-open and the various with-connection macros. it's worth double checking this assumption before submitting your results of course. It would be much more difficult if the macro was supposed to find closable values in its body with out at least some knowledge of its structure.
with-open macro does exactly the same thing.
If there is variable (can be more than one) bound to created object it wraps the body to try-catch block with finallyclosing.
(macroexpand-1 '(with-open [f (FileReader. (File. "1.txt"))]
(do this with f)
(do that with f)))
=>
(clojure.core/let
[f (FileReader. (File. "1.txt"))]
(try (clojure.core/with-open []
(do this with f)
(do that with f))
(finally (. f clojure.core/close))))
If there are no bindings then it just returns the body
(macroexpand-1 '(with-open []
(do this with f)
(do that with f)))
=>
(do (do this with f)
(do that with f))
Update. Arthur has already explained "exception" part of your question.
I am trying to implement a huge Java interface with numerous (~50) getter and setter methods (some with irregular names). I thought it would be nice to use a macro to reduce the amount of code. So instead of
(def data (atom {:x nil}))
(reify HugeInterface
(getX [this] (:x #data))
(setX [this v] (swap! data assoc :x v)))
I want to be able to write
(def data (atom {:x nil}))
(reify HugeInterface
(set-and-get getX setX :x))
Is this set-and-get macro (or something similar) possible? I haven't been able to make it work.
(Updated with a second approach -- see below the second horizontal rule -- as well as some explanatory remarks re: the first one.)
I wonder if this might be a step in the right direction:
(defmacro reify-from-maps [iface implicits-map emit-map & ms]
`(reify ~iface
~#(apply concat
(for [[mname & args :as m] ms]
(if-let [emit ((keyword mname) emit-map)]
(apply emit implicits-map args)
[m])))))
(def emit-atom-g&ss
{:set-and-get (fn [implicits-map gname sname k]
[`(~gname [~'this] (~k #~(:atom-name implicits-map)))
`(~sname [~'this ~'v]
(swap! ~(:atom-name implicits-map) assoc ~k ~'v))])})
(defmacro atom-bean [iface a & ms]
`(reify-from-maps ~iface {:atom-name ~a} ~emit-atom-g&ss ~#ms))
NB. that the atom-bean macro passes the actual compile-time value of emit-atom-g&ss on to reify-from-maps. Once a particular atom-bean form is compiled, any subsequent changes to emit-atom-g&ss have no effect on the behaviour of the created object.
An example macroexpansion from the REPL (with some line breaks and indentation added for clarity):
user> (-> '(atom-bean HugeInterface data
(set-and-get setX getX :x))
macroexpand-1
macroexpand-1)
(clojure.core/reify HugeInterface
(setX [this] (:x (clojure.core/deref data)))
(getX [this v] (clojure.core/swap! data clojure.core/assoc :x v)))
Two macroexpand-1s are necessary, because atom-bean is a macro which expands to a further macro call. macroexpand would not be particularly useful, as it would expand this all the way to a call to reify*, the implementation detail behind reify.
The idea here is that you can supply an emit-map like emit-atom-g&ss above, keyed by keywords whose names (in symbolic form) will trigger magic method generation in reify-from-maps calls. The magic is performed by the functions stored as functions in the given emit-map; the arguments to the functions are a map of "implicits" (basically any and all information which should be accessible to all method definitions in a reify-from-maps form, like the name of the atom in this particular case) followed by whichever arguments were given to the "magic method specifier" in the reify-from-maps form. As mentioned above, reify-from-maps needs to see an actual keyword -> function map, not its symbolic name; so, it's only really usable with literal maps, inside other macros or with help of eval.
Normal method definitions can still be included and will be treated as in a regular reify form, provided keys matching their names do not occur in the emit-map. The emit functions must return seqables (e.g. vectors) of method definitions in the format expected by reify: in this way, the case with multiple method definitions returned for one "magic method specifier" is relatively simple. If the iface argument were replaced with ifaces and ~iface with ~#ifaces in reify-from-maps' body, multiple interfaces could be specified for implementation.
Here's another approach, possibly easier to reason about:
(defn compile-atom-bean-converter [ifaces get-set-map]
(eval
(let [asym (gensym)]
`(fn [~asym]
(reify ~#ifaces
~#(apply concat
(for [[k [g s]] get-set-map]
[`(~g [~'this] (~k #~asym))
`(~s [~'this ~'v]
(swap! ~asym assoc ~k ~'v))])))))))
This calls on the compiler at runtime, which is somewhat expensive, but only needs to be done once per set of interfaces to be implemented. The result is a function which takes an atom as an argument and reifies a wrapper around the atom implementing the given interfaces with getters and setters as specified in the get-set-map argument. (Written this way, this is less flexible than the previous approach, but most of the code above could be reused here.)
Here's a sample interface and a getter/setter map:
(definterface IFunky
(getFoo [])
(^void setFoo [v])
(getFunkyBar [])
(^void setWeirdBar [v]))
(def gsm
'{:foo [getFoo setFoo]
:bar [getFunkyBar setWeirdBar]})
And some REPL interactions:
user> (def data {:foo 1 :bar 2})
#'user/data
user> (def atom-bean-converter (compile-atom-bean-converter '[IFunky] gsm))
#'user/atom-bean-converter
user> (def atom-bean (atom-bean-converter data))
#'user/atom-bean
user> (.setFoo data-bean 3)
nil
user> (.getFoo atom-bean)
3
user> (.getFunkyBar data-bean)
2
user> (.setWeirdBar data-bean 5)
nil
user> (.getFunkyBar data-bean)
5
The point is reify being a macro itself which is expanded before your own set-and-get macro - so the set-and-get approach doesn't work. So, instead of an inner macro inside reify, you need a macro on the "outside" that generates the reify, too.
Since the trick is to expand the body before reify sees it, a more general solution could be something along these lines:
(defmacro reify+ [& body]
`(reify ~#(map macroexpand-1 body)))
You can also try to force your macro to expand first:
(ns qqq (:use clojure.walk))
(defmacro expand-first [the-set & code] `(do ~#(prewalk #(if (and (list? %) (contains? the-set (first %))) (macroexpand-all %) %) code)))
(defmacro setter [setterf kw] `(~setterf [~'this ~'v] (swap! ~'data assoc ~kw ~'v)))
(defmacro getter [getterf kw] `(~getterf [~'this] (~kw #~'data)))
(expand-first #{setter getter}
(reify HugeInterface
(getter getX :x)
(setter setX :x)))