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.
Related
I would like a more detailed explanation of how macro expansion works, at least in Emacs Lisp but an overview of other Lisps would be appreciated. The way I usually see it explained is that the arguments of the macro are passed unevaluated to the body, which is then executed and returns a new LISP form. However, if I do
(defun check-one (arg)
(eq arg 1))
(defmacro check-foo (checker foo)
(if (checker 1)
`(,foo "yes")
`(,foo "no")))
I would expect
(check-foo check-one print)
to first expand to
(if (check-one 1)
`(print "yes")
`(print "no))
and then finally to
(print "yes")
but instead I get a "checker" function is void error. On the other hand, if I had defined
(defmacro check-foo (checker foo)
(if (funcall checker 1)
`(,foo "yes")
`(,foo "no")))
then I would have the expected behavior. So the expressions do get replaced in the body unevaluated, but for some reason functions do not work? What is the step-by-step procedure the interpreter follows when macroexpanding? Is there a good text-book that explains this rigorously?
Macros are functions ...
A good way to think about macros is that they are simply functions, like any other function.
... which operate on source code
But they are functions whose arguments are source code, and whose value is also source code.
Looking at macro functions
Macros being functions is not quite explicit in elisp: some of the lower-level functionality is, I think, not exposed. But in Common Lisp this is quite literally how macros are implemented: a macro has an associated function, and this function gets called to expand the macro, with its value being the new source code. For instance, if you are so minded you could write macros in Common Lisp like this.
(defun expand-fn (form environment)
;; not talking about environment
(declare (ignore environment))
(let ((name (second form))
(arglist (third form))
(body (cdddr form)))
`(function (lambda ,arglist
(block ,name
,#body)))))
(setf (macro-function 'fn) #'expand-fn)
And now fn is a macro which will construct a function which 'knows its name', so you could write
(fn foo (x) ... (return-from foo x) ...)
which turns into
(function (lambda (x) (block foo ... (return-from foo x))))
In Common Lisp, defmacro is then itself a macro which arranges for a suitable macro function to be installed and also deals with making the macro available at compile time &c.
In elisp, it looks as if this lower layer is not specified by the language, but I think it's safe to assume that things work the same way.
So then the job of a macro is to take a bunch of source code and compute from it another bunch of source code which is the expansion of the macro. And of course the really neat trick is that, because source code (both arguments and values) is represented as s-expressions, Lisp is a superb language for manipulating s-expressions, you can write macros in Lisp itself.
Macroexpansion
There are a fair number of fiddly corner cases here such as local macros and so on. But here is, pretty much, how this works.
Start with some form <f>:
If <f> is (<a> ...) where <a> is a symbol, check for a macro function for <a>. If it has one, call it on the whole form, and call the value it returns <f'>: now simply recurse on <f'>.
If <f> is (<a> ...) where <a> is a symbol which names a special operator (something like if) then recurse on the subforms of the special operator which its rules say must be macroexpanded. As an example, in a form like (if <x> <y> <z>) all of <x>, <y>, & <z> need to be macroexpanded, while in (setq <a> <b>), only <b> would be subject to macroexpansion, and so on: these rules are hard-wired, which is why special operators are special.
If <f> is (<a> ...) where <a> is a symbol which is neither of the above cases, then it's a function call, and the forms in the body of the form are macroexpanded, and that's it.
If <f> is ((lambda (...) ...) ...) then the forms in the body of the lambda (but not its arguments!) are macroexpanded and then the case is the same as the last one.
Finally <f> might not be a compound form: nothing to do here.
I think that's all the cases. This is not a complete description of the process because there are complications like local macros and so on. But it's enough I think.
Order of macroexpansion
Note that macroexpansion happens 'outside in': a form like (a ...) is expanded until you get something which isn't a macro form, and only then is the body, perhaps, expanded. That's because, until the macro is completely expanded, you have no idea which, if any, of the subforms are even eligible for macroexpansion.
Your code
My guess is that what you want to happen is that (check-foo bog foo) should turn into (if (bog 1) (foo yes) (foo no)). So the way to get this is that this form is what the macro function needs to return. We could write this using the CL low-level facilities:
(defun check-foo-expander (form environment)
;; form is like (check-foo pred-name function-name)
(declare (ignore environment)) ;still not talking about environment
`(if (,(second form) 1)
(,(third form) "yes")
(,(third form) "no")))
And we can check:
> (check-foo-expander '(check-foo bog foo) nil)
(if (bog 1) (foo "yes") (foo "no"))
And then install it as a macro:
> (setf (macro-function 'check-foo) #'check-foo-expander)
And now
> (check-foo evenp print)
"no"
"no"
> (check-foo oddp print)
"yes"
"yes"
But it's easier to write it using defmacro:
(defmacro check-foo (predicate function)
`(if (,predicate 1)
(,function "yes")
(,function "no")))
This is the same thing (more-or-less), but easier to read.
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 new to lisp, and am learning as I go.
The standard common lisp break function 1. pops you into the debugger, and 2. if you choose to continue, returns nil.
It seems to me that a break function that popped you into the debugger but RETURNED ITS INPUT would be extremely useful. Then, you could just insert it transparently around a given s-expression to look at the state of the program at that point.
So I could do something like
CL-USER> (break-transparent (+ 1 2))
which would pop me into the debugger and let me look around and then would return
3
Is there such a thing in lisp, and, if not, is there a way to make such a thing? I am not good with macros yet.
Thanks,
EDIT:
Doug Currie kindly answered this below with a simple macro. Here is my slightly modified version for anyone else with this question that displays the argument to break-transparent front and center in the debugger window.
(defmacro break-transparent (exp)
`(let ((x ,exp)) (break "argument to break: ~:S" x) x))
You can write break-transparent as a macro that expands to:
(progn
(break)
(+ 1 2))
or if you really want to evaluate the expression before the break:
(let ((x (+ 1 2)))
(break)
x)
So,
(defmacro (break-transparent exp)
`(let ((x ,exp)) (break) x))
Since you've added the macro from the other answer to your question in a slightly modified version, here's a fixed version of that that doesn't add a new identifer that might interfere with an existing one:
(defmacro break-transparent (value)
(let ((g (gensym)))
`(let ((,g ,value))
(break "argument to break: ~:S" ,g)
,g)))
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))))
In clojure, macros give a tremendous power to the programmer. eval also is very powerful. There exist some subtle differences between the two. I hope that this riddle will shine some light on this topic.
(ns hello)
(defmacro my-eval [x] `~(read-string x))
(defn hello[] "Hello")
(defn run-stuff []
(println (hello))
(println (my-eval "(hello)"))
(println (eval (read-string "(hello)"))))
(ns main)
(try (hello/run-stuff)
(catch Exception e (println e)))
Over the 3 statements inside run-stuff body, which one causes an exception and why the other ones don't?
I have formulated the following riddle following the investigation of this beautiful question Clojure - (read-string String calling function. Thanks to #Matthias Benkard for the clarifications
(println (hello)) and (println (my-eval "(hello)")) are completely identical statements -- the only difference is that one will confuse your editor more. my-eval is NOT comparable to the real eval. The difference is that the argument to my-eval needs to be a string at compile time -- the following errors out because the symbol x can't be cast to a string.
(def x "(hello)")
(my-eval x)
This makes my-eval utterly pointless - you can "eval" a literal string or you can remove the quotes and the my-eval and have equally functional code (that your editor will understand).
Real eval, on the other hand, tries to compile code at run time. Here, it fails because it is being run from the main namespace, not the hello namespace, as #Matthias Benkard pointed out.