Is there a way to print the result of evaluating nested syntax quotes in a legible manner as in SBCL? This would be useful when debugging nested syntax quotes when writing macros. For instance, in Clojure 1.8,
(let [x '(1 2)] ``(~~#x))
evaluates to
(clojure.core/seq (clojure.core/concat (clojure.core/list 1 2)))
In SBCL 1.3.6, the equivalent expression
(let ((x '(1 2))) ``(,,#x))
evaluates to the much more legible
`(,1 ,2)
The difference becomes larger with more complex expressions. Are there any Clojure packages or other methods that can help with this situation? Currently, the best way I've found to debug complex syntax quotes is to convert them to Common Lisp but this is a rather ridiculous and slow approach.
If you look the function syntaxQuote(Object form)in the LispReader Class of Clojure :
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L1011
ISeq seq = RT.seq(form);
if(seq == null)
ret = RT.cons(LIST,null);
else
ret = RT.list(SEQ, RT.cons(CONCAT, sqExpandList(seq)));
you'll see that `(~#'(some list)) is read as :
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote clojure.core/some))
(clojure.core/list (quote clojure.core/list))))
Which is evaluated by the REPL as :
=> (some list)
Just look at the effect of ` alone
`s => user/s ; it's the ref of the symbol ok
``s
=> (quote user/s) ; it's the quoted ref
```s
=> (clojure.core/seq ; now we manage a back-tick on a list
(clojure.core/concat
(clojure.core/list (quote quote))
(clojure.core/list (quote user/s))))
````s
=>
(clojure.core/seq ; oups! always a list we add a layer
(clojure.core/concat
(clojure.core/list (quote clojure.core/seq))
(clojure.core/list
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote clojure.core/concat))
(clojure.core/list
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote clojure.core/list))
(clojure.core/list
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote quote))
(clojure.core/list (quote quote))))))))
(clojure.core/list
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote clojure.core/list))
(clojure.core/list
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote quote))
(clojure.core/list (quote user/s)))))))))))))
And now adding the splicing
````~s => (clojure.core/seq ; same as ```s
(clojure.core/concat
(clojure.core/list (quote quote))
(clojure.core/list (quote user/s))))
````~~s => (quote user/s) ; same as ``s
So what are the remarks to make
Clojure writer doesn't render quotes as received by the reader macro
so it gives (quote s) instead of 's. This is done for arrays, set, ...
The back-tick macro reader doesn't make simplification on list/quote matching. Concatenation of only quoted lists and single entries should be executed immediately, giving
````~~s => ''s.
The problem is even worse if you manage back-ticking on lists or arrays or sets... ;)
The problem is that `s is not 's.
If I remember in LISP `s gives 's as a result. ;)
A possibility to manage a simplified version can be viewed so
(clojure.core/seq
(clojure.core/concat
(clojure.core/list (quote quote))
(clojure.core/list (quote user/s))))
could be changed in the macro generation as
(seq 'user/s)
But!!! the result is a sequence, say a lazy sequence, not 'user/s.
Let's try on ````s. simplifying would give :
(seq '(clojure.core/seq 'user/s))
The result is equivalent to ''s, but it isn't the same object.
Another thing, we have to manage the toString of (quote ...) as '...
And contrary to LISP 's is s and `s is user/s !!!
And for macro management, it makes a lot of changes... Say 's is in the execution namespace, `s is in the compilation namespace, executed by the reader.
Related
(def a (edn/read-string "(+ 1 3)"))
; => (+ 1 3)
How do I evaluate this resulting list?
(type (first a))
; => cljs.core/Symbol
(= (first a) '+)
; => true
I suppose more generally how would I get from symbol -> function.
And is this a normal practice in clojure? I can't seem to find anything on it. Perhaps I'm not searching with the correct terms.
You'd normally use eval. But in ClojureScript, you'd need the compiler and standard lib available at runtime. This is only possible if you are making use of self-hosted ClojureScript.
If you are in a self-hosted environment (such as Lumo, Planck, Replete, Klipse, etc.), then eval will just work:
cljs.user=> (require '[clojure.edn :as edn])
nil
cljs.user=> (def a (edn/read-string "(+ 1 3)"))
#'cljs.user/a
cljs.user=> (eval a)
4
Otherwise, you can make use of the facilities in the cljs.js namespace to access self-hosted ClojureScript:
cljs.user=> (require 'cljs.js)
nil
cljs.user=> (cljs.js/eval (cljs.js/empty-state)
a {:eval cljs.js/js-eval :context :expr} prn)
{:value 4}
Note that doing this carries some size considerations: The ClojureScript compiler will be brought with your compiled artifacts into the target environment, and you must also avoid using :advanced, ensuring that the entire cljs.core standard lib and associated metadata is available at runtime.
My answer seems to only work in Clojure, not ClojureScript. See the other answer.
I think you may be looking for resolve.
(defn my-simple-eval [expr]
; Cut the function symbol from the arguments
(let [[f & args] (edn/read-string expr)]
; Resolve f to a function then apply the supplied arguments to it
(apply (resolve f) args)))
(my-simple-eval "(+ 1 3)")
=> 4
The arguments must be bare numbers for this to work though. If you want to allow for sub-expressions, you could make it recursive:
(defn my-simple-eval-rec [expr]
(letfn [(rec [[f & args]]
(->> args
(map (fn [arg]
(if (list? arg)
(rec arg) ; Process the sub-expr
arg)))
(apply (resolve f))))]
(rec (edn/read-string expr))))
(my-simple-eval-rec "(+ 1 (+ 2 5))")
=> 8
If this doesn't suffice though, I don't know of any way other than using eval:
(def a (edn/read-string "(+ 1 3)"))
(eval a)
=> 4
or, if the data is available at the time macros are expanded, you could just wrap the call to read-string to have the data interpreted as normal:
(defmacro my-read-string [expr]
(edn/read-string expr))
(my-read-string "(+ 1 3)")
=> 4
http://clojure.org/metadata says "Symbols and collections support metadata"
So I try to set metadata to a symbol:
=> a
17
=> (def aa ^a 'x)
=> aa
x
=> (meta aa)
nil
It does not work as I expected.
=> (def aa ^a [])
=> (meta aa)
{:tag 17}
This does.
Is this a mistake in the documentation? If not, can you please explain?
Update after answer by Arthur Ulfeldt: So I understand it as follows. When I wrote
(def aa ^a 'x)
the reader expanded it into
(def aa ^a (quote x))
so the metadata were at the list (quote x), and not at the symbol. When evaluating the def macro, this list got evaluated, leaving us with x, and the metadata were lost.
It works if instead of using the quote reader macro you write out the (quote x) expression and then attach the metadata to the symbol within the quote:
user> (def aa (quote ^unevaluated-symbol x))
#'user/aa
user> (meta aa)
{:tag unevaluated-symbol}
It's worth noting that when you put the symbol with the quote it never gets a chance to be evaluated. if you want it evaluated you can skip the whole quoting and generate the symbol with the symbol function:
user> (def aa (with-meta (symbol "x") {:foo a}))
#'user/aa
user> (meta aa)
{:foo 17}
Why don't when-let and if-let support multiple bindings by default?
So:
(when-let [a ...
b ...]
(+ a b))
...instead of:
(when-let [a ...
(when-let [b ...
(+ a b)))
I am aware that I can write my own macro or use a monad (as described here: http://inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html).
Because (for if-let, at least) it's not obvious what to do with the "else" cases.
At least, motivated by Better way to nest if-let in clojure I started to write a macro that did this. Given
(if-let* [a ...
b ...]
action
other)
it would generate
(if-let [a ...]
(if-let [b ...]
action
?))
and it wasn't clear to me how to continue (there are two places for "else").
You can say that there should be a single alternative for any failure, or none for when-let, but if any of the tests mutate state then things are still going to get messy.
In short, it's a little more complicated than I expected, and so I guess the current approach avoids having to make a call on what the solution should be.
Another way of saying the same thing: you're assuming if-let should nest like let. A better model might be cond, which isn't a "nested if" but more an "alternative if", and so doesn't fit well with scopes... or, yet another way of saying it: if doesn't handle this case any better.
Here is when-let*:
(defmacro when-let*
"Multiple binding version of when-let"
[bindings & body]
(if (seq bindings)
`(when-let [~(first bindings) ~(second bindings)]
(when-let* ~(vec (drop 2 bindings)) ~#body))
`(do ~#body)))
Usage:
user=> (when-let* [a 1 b 2 c 3]
(println "yeah!")
a)
;;=>yeah!
;;=>1
user=> (when-let* [a 1 b nil c 3]
(println "damn! b is nil")
a)
;;=>nil
Here is if-let*:
(defmacro if-let*
"Multiple binding version of if-let"
([bindings then]
`(if-let* ~bindings ~then nil))
([bindings then else]
(if (seq bindings)
`(if-let [~(first bindings) ~(second bindings)]
(if-let* ~(vec (drop 2 bindings)) ~then ~else)
~else)
then)))
Usage:
user=> (if-let* [a 1
b 2
c (+ a b)]
c
:some-val)
;;=> 3
user=> (if-let* [a 1 b "Damn!" c nil]
a
:some-val)
;;=> :some-val
EDIT: It turned out bindings should not be leaked in the else form.
If you use cats, then there is a mlet function that you might find useful :
(use 'cats.builtin)
(require '[cats.core :as m])
(require '[cats.monad.maybe :as maybe])
(m/mlet [x (maybe/just 42)
y nil]
(m/return (+ x y)))
;; => nil
As you can see, the mlet short-circuits when encountering a nil value.
(from section 6.5.1 nil)
So I thought it would be a nice idea to name a function that calculates the exponential ^, but it seems like the caret actually does something special, as the Clojure REPL generates an error when evaluating '^. Googling mostly gave me this, so I was wondering what the actualy use for the caret in Clojure is.
(Also, would it be possible after all to name a function ^?)
^ is "the meta character" it tells the reader to add the symbol starting with ^ as metadata to the next symbol (provided it is something that implements IMetas)
user=> (def x ^:IamMeta [1 2 3])
#'user/x
user=> x
[1 2 3]
user=> (meta x)
{:tag :IamMeta}
user=>
You can learn a lot about how clojure works under the hood by looking at the meta of things, for instance functions:
user=> (meta foo)
{:ns #<Namespace user>,
:name foo, :file "NO_SOURCE_PATH",
:line 5, :arglists ([s])}
this is very often used for type hints
(defn foo [^String s] (.charAt s 1))
it is generally a good idea to turn on reflection warnings (set! *warn-on-reflection* true) and then add type hints until the warnings go away. without these Clojure will look up the type of the function operands at run-time, which saves you the trouble of fussing with types though at a slight cost.
PS: My next favorite reader character is the "dispatch" character #, it is well worth learning about it next :)
PPS: this is different in clojure 1.2.x vs clojure 1.3.x
in Clojure 1.2.1 metadata does not compose when you use the meta-character:
user=> (def foo ^:foo ^:bar [1 2 3])
#'user/foo
user=> (meta foo)
{:tag :foo}
and in 1.3 it "does the right thing" and also keywords are options instead of "tags":
user=> (def foo ^:foo ^:bar [1 2 3])
#'user/foo
user=> (meta foo)
{:foo true, :bar true}
It seems to me that the answer to your question is, unfortunately, no. In Clojure, you cannot name a function ^.
I tried the following in the REPL:
user=> (println \^)
^
nil
This seems to imply that you can escape the carat (^) with a backslash. However, if I try to declare a function using \^ as a name then I get an error message:
user=> (defn \^ [n e] (cond (= e 0) 1 :else (* n (\^ n (- e 1)))))
IllegalArgumentException First argument to defn must be a symbol
clojure.core/defn (core.clj:277)
The same code works with a regular text name:
user=> (defn exp [n e] (cond (= e 0) 1 :else (* n (exp n (- e 1)))))
#'user/exp
user=> (exp 3 3)
27
I would be delighted if someone with better Clojure-fu than mine could prove me wrong! :)
It seems to be a powerful macro, yet I'm failing to apply it to anything but silly examples. Can you show me some real use of it?
Thanks!
Compare:
user> (:baz (:bar (:foo {:foo {:bar {:baz 123}}})))
123
user> (java.io.BufferedReader. (java.io.FileReader. "foo.txt"))
#<BufferedReader java.io.BufferedReader#6e1f8f>
user> (vec (reverse (.split (.replaceAll (.toLowerCase "FOO,BAR,BAZ") "b" "x") ",")))
["xaz" "xar" "foo"]
to:
user> (-> {:foo {:bar {:baz 123}}} :foo :bar :baz)
123
user> (-> "foo.txt" java.io.FileReader. java.io.BufferedReader.)
#<BufferedReader java.io.BufferedReader#7a6c34>
user> (-> "FOO,BAR,BAZ" .toLowerCase (.replaceAll "b" "x") (.split ",") reverse vec)
["xaz" "xar" "foo"]
-> is used when you want a concise way to nest calls. It lets you list the calls in the order they'll be called rather than inside-out, which can be more readable. In the third example, notice how much distance is between some of the arguments and the function they belong to; -> lets you group arguments and function calls a bit more cleanly. Because it's a macro it also works for Java calls, which is nice.
-> isn't that powerful, it just saves you a few parens now and then. Using it or not is a question of style and readability.
Look at the bottom of clojure.zip for extreme examples of how this is helpful.
(-> dz next next next next next next next next next remove up (append-child 'e) root)
Taken from the wiki I've always found this example impressive:
user=> (import '(java.net URL) '(java.util.zip ZipInputStream))
user=> (-> "http://clojure.googlecode.com/files/clojure_20081217.zip"
URL. .openStream ZipInputStream. .getNextEntry bean :name)
As Brian said - it isn't 'useful' so much as 'different style'. I find for all java interop this form of 'start with X' then do Y and Z ... more readable than do Z to Y of X.
Basically you have 4 options:
; imperative style named steps:
(let [X something
b (Y X)
c (Z b)] c)
; nested calls
(Z (Y X))
; threaded calls
(-> X Y Z)
; functional composition
((comp Z Y) X)
I find -> really shines for java interop but avoid it elsewhere.
(defn search-tickets-for [term]
(-> term search zip-soup first :content
((partial filter #(= :body (:tag %)))) first :content
((partial filter #(= :div (:tag %))))
((partial filter #(= "content" ((comp :id :attrs) %))))
((partial map :content)) first ((partial map :content))
((partial map first)) ((partial filter #(= :ul (:tag %)))) first :content
((partial map :content))
((partial map first))
((partial mapcat :content))
((partial filter #(= :h4 (:tag %))))
((partial mapcat :content))
((partial filter #(= :a (:tag %))))
((partial mapcat :content))))
clojurebot from #clojure uses this to search assembla tickets