(let [a (clojure.core.async/chan)]
(case a
a :foo
:bar))
#=> :bar
I would expect :foo here. What am I doing wrong?
On the other hand (condp = chan ...) does the job.
PS:
Basically I am trying to do following thing:
(require '[clojure.core.async :as a])
(let [chan1 (a/chan 10)
chan2 (a/chan 10)]
(a/>!! chan1 true)
(let [[v c] (a/alts!! [chan1 chan2])]
(case c
chan1 :chan1
chan2 :chan2
:niether)))
#=> :neither
The docs for case have the answer
The test-constants are not evaluated. They must be compile-time
literals, and need not be quoted.
The correct solution is to use cond:
(let [chan1 (ca/chan 10)
chan2 (ca/chan 10)]
(ca/>!! chan1 true)
(let [[v c] (ca/alts!! [chan1 chan2])]
(spyx (cond
(= c chan1) :chan1
(= c chan2) :chan2
:else :neither))))
;=> :chan1
Case uses unevaluated test-constants for the left-hand-side of the clause. Plain symbols, like chan1 here will match only the symbol with the same name, not the value of the local binding with that name; chan1 will match 'chan1
Related
This macro returns the values of the "magic" &env as a map, so that
(let [xyz "ZYX"] (get-env)) returns {xyz "ZYX"}, where the key is a Symbol.
(defmacro get-env []
(let [ks (keys &env)]
`(zipmap '~ks [~#ks])))
The expression '~ks evaluates the ks into Symbols at the macro-expansion phase (right?), but then quotes the expansion, so that the Symbols don't get evaluated into their values ("ZYX" in our example), but rather stay as Symbols (xyz). Is that right?
About [~#ks]: It evaluates ks into an seq of Symbols at the macro-expansion phase (right?) (and splices them and forms a vector with []). But how does that allow these Symbols to get further evaluated into their values ("ZYX" in our example) -- is there a second evaluation step, applied immediately after the first?
Another variant is
(defmacro local-env [] (->> (keys &env)
(map (fn [k] [(list 'quote k) k])) (into {})))
Your macro takes all the keys from the env. Then it uses the keys (a
list of symbols) to zip both the list of keys with spliced symbols
inside a vector. So what you get from
(let [x 42]
(get-env))
is
(let [x 42]
(zipmap '(x) [x]))
This is a compile-time transformation of your code (the whole point of
macros). The resulting code at runtime will use the 42 from the bound
x.
Preface
You may also be interested in the book "Clojure Macros", and in this StackOverflow question:
How do I write a Clojure threading macro?
Discussion
When in doubt, ask the compiler. Consider this code using my favorite template project:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defmacro getenv []
(prn :env &env)
(prn :env-meta (meta &env))
(prn :form &form)
(prn :form-meta (meta &form)))
(defn go []
(newline)
(prn :01)
(getenv)
(let [x 1
y "yyy"]
(newline)
(prn :02)
(getenv))
)
(dotest
(go))
with output
:env nil
:env-meta nil
:form (getenv)
:form-meta {:line 15, :column 3}
:env {x #object[clojure.lang.Compiler$LocalBinding 0x1ab07559 "clojure.lang.Compiler$LocalBinding#1ab07559"], y #object[clojure.lang.Compiler$LocalBinding 0x26c79134 "clojure.lang.Compiler$LocalBinding#26c79134"]}
:env-meta nil
:form (getenv)
:form-meta {:line 21, :column 5}
Testing tst.demo.core
:01
:02
so we can see the 4 (prn ...) outputs for each call to getenv. In the case where there are no local bindings, we get
&env ;=> nil
and for the case with the let we get a map like
(let [env-val (quote
{x :compiler-local-1
y :compiler-local-1})
ks (keys env-val)
ks-vec [ks]
]
(spyx env-val)
(spyx ks)
(spyx ks-vec)
)
with result
env-val => {x :compiler-local-1, y :compiler-local-1}
ks => (x y)
ks-vec => [(x y)]
At this point, I'm not quite sure what your desired result is. Could you modify the question to add that?
BTW, there is no hidden 2nd step, if I understand your question correctly.
Also
I rewrite your local-env and got the following result:
(defmacro local-env []
(prn :into-result
(into {}
(mapv
(fn [k] [(list 'quote k) k])
(keys &env)))))
(let [x 1
y "yyy"]
(newline)
(prn :03)
(local-env))
with result
:into-result {(quote x) x,
(quote y) y}
so I think there is some confusion here.
In Clojure, is there a way to make a var constant such that it can be used in case statements?
e.g.
(def a 1)
(def b 2)
(let [x 1]
(case x
a :1
b :2
:none))
=> :none
I understand I can use something like cond or condp to get around this, but it would be nice if I could define something that does not require further evaluation so I could use case.
Related and answer stolen from it:
As the docstring tells you: No you cannot do this. You can use Chas Emericks macro and do this however:
(defmacro case+
"Same as case, but evaluates dispatch values, needed for referring to
class and def'ed constants as well as java.util.Enum instances."
[value & clauses]
(let [clauses (partition 2 2 nil clauses)
default (when (-> clauses last count (== 1))
(last clauses))
clauses (if default (drop-last clauses) clauses)
eval-dispatch (fn [d]
(if (list? d)
(map eval d)
(eval d)))]
`(case ~value
~#(concat (->> clauses
(map #(-> % first eval-dispatch (list (second %))))
(mapcat identity))
default))))
Thus:
(def ^:const a 1)
(def ^:const b 2)
(let [x 1]
(case+ x
a :1
b :2
:none))
=> :1
An alternative (which is nice since it's more powerful) is to use core.match's functionality. Though you can only match against local bindings:
(let [x 2
a a
b b]
(match x
a :1
b :2
:none))
=> :2
You can also use clojure.core/condp for the job:
(def a 1)
(def b 2)
(let [x 1]
(condp = x
a :1
b :2
:none))
#=> :1
What would be the idiomatic way of writing the following function ?
(split-first #"." "abc.def.ghi") ;;=>["abc", "def.ghi"]
(split-last #"." "abc.def.ghi") ;;=>["abc.def", "ghi"]
There is an obvious (ugly ?) solution using split, but I'm sure there are more elegant solutions ? Maybe using regexes/indexOf/split-with ?
For split-first, the best approach would be:
(defn split-first [re s]
(clojure.string/split s re 2))
(split-first #"\." "abc.def.ghi")
=> ["abc" "def.ghi"]
(split-first #"<>" "abc<>def<>ghi")
=> ["abc" "def<>ghi"]
One approach for split-last is to use a negative lookahead assertion:
(defn split-last [re s]
(let [pattern (re-pattern (str re "(?!.*" re ")"))]
(split-first pattern s)))
(split-last #"\." "abc.def.ghi")
=> ["abc.def" "ghi"]
(split-last #"<>" "abc<>def<>ghi")
=> ["abc<>def" "ghi"]
If you do not necessarily need regexp matching this would work:
(defn index-of
[^String s c]
(.indexOf s c))
(defn last-index-of
[^String s c]
(.lastIndexOf s c))
(defn split-at-index-fn
[f c s]
(let [i (f s c)]
; I do not know what you want returned if no match is found
(when-not (neg? i)
[(.substring s 0 i) (.substring s (inc i))])))
(def split-first
(partial split-at-index-fn index-of))
(def split-last
(partial split-at-index-fn last-index-of))
This is not quite idiomatic, because it is mostly just Java interop.
I want to write a macro named $=> to transfer the code like:
(let [bb 11] ($=> #"aa#{bb}")) => ["aa?" 11]
which means that I want to splite all string after # with the pattern #\{.*?\}
and replace the pattern with ? and then eval the symbal of the patten.
So I write the macro like this:
(defmacro parser [clause]
(if (and (sequential? clause)
(= 2 (count clause))
(= `deref (first clause))
(string? (second clause)))
(let [s (second clause)
regx# #"#\{(.*?)\}"
m# (re-matcher regx# s)
p# (take-while #(not (nil? %)) (repeatedly #(second (re-find m#))))
ss# (clojure.string/replace s #"#\{(.*?)\}" "?" )
ps# (map symbol p#)]
`[~ss# ~#ps#])
clause))
This macro works well
user=> (let [aa 11] (parser #"AAA#{aa}" ))
["AAA?" 11]
user=> (let [aa 11] (parser #"AA{aa}" ))
["AA{aa}"]
But I want the macro $=> can transfer all of the pattern in the code , like:
(let [a 1 b 2 c 3]
($=> #"AAA#{a}"
(if true #"BBB#{b}")
(for [i (range 1)] #"CCC#{c}")))
and it can return
[["AAA?" 1] ["BBB?" 2] (["CCC?" 3])]
I have tried some method and all of them failed.
Now I have no idea how to solve this problem.
What's the problem with following code:
the func expression get expression that contains term that can contain expression...
(defn term[]
(def mytmp (zip/xml-zip {:tag :term}))
(cond
(= (first(:content(first vecTok))) "(")
(do
(def mytmp (popVecTo mytmp))
(def mytmp (zip/append-child mytmp (expression)))
(def mytmp (popVecTo mytmp)))
:else
(def mytmp (popVecTo mytmp)))
(zip/node mytmp))
(defn expression[]
(def mytmp (zip/xml-zip {:tag :expression}))
(def mytmp (zip/append-child mytmp (term)))
(while (contains? #{"+", "-", "*","/", "&", "|", "<", ">", "="} (first(:content(first vecTok))) )
(do
(def mytmp (popVecTo mytmp))
(def mytmp (zip/append-child mytmp (term)))))
(zip/node mytmp))
(def vecTok (vec (:content(first(xml-seq (parse "C:/Users/User/Desktop/forHekronot/BallT.xml"))))))
In the file :
<a><symbol>(</symbol><identifier>dy</identifier><symbol>-</symbol><identifier>dx</identifier><symbol>)</symbol></a>
Notwithstanding #jszakmeister's comment on how to better solve the problem, let me try to give and answer to the question:
you can first (def expression) and then (defn term [] ...) and finally (defn expression [] ...).
The classic example for indirect recursion is of course the poor man's odd/even function for positive numbers:
clojurec.core=> (def even)
#'clojurec.core/even
clojurec.core=> (defn odd [x] (and (not (= x 0)) (even (dec x))))
#'clojurec.core/odd
clojurec.core=> (defn even [x] (or (= x 0) (odd (dec x))))
#'clojurec.core/even
clojurec.core=> (even 10)
true
clojurec.core=> (odd 10)
false
clojurec.core=> (odd 10000)
StackOverflowError clojure.lang.Numbers.equal (Numbers.java:214)
Ooops, depending on the size (or rather depth) of your file this could be a problem. But not all is lost, we can redefine even to use trampoline internally:
(defn even [n]
(letfn [(evenrec [x] (or (= x 0) #(oddrec (dec x))))
(oddrec [x] (and (not (= x 0)) #(evenrec (dec x))))]
(trampoline evenrec n)))