本文共 8936 字,大约阅读时间需要 29 分钟。
user=> (defmacro foreach [[sym coll] & body] `(loop [coll# ~coll] (when-let [[~sym & xs#] (seq coll#)] ~@body (recur xs#))))#'user/foreachuser=>user=> (foreach [x [1 2 3]] (println x))123niluser=>
Syntax-quote (`, note, the "backquote" character), Unquote (~) and Unquote-splicing (~@) For all forms other than Symbols, Lists, Vectors, Sets and Maps, `x is the same as 'x.
user=> (defmacro dbg[x] `(let [x# ~x] (println '~x "=" x#) x#)) user=> (def x 5)user=> (def lst '(a b c))user=> `(fred x ~x lst ~@lst 7 8 :nine) (user/fred user/x 5 user/lst a b c 7 8 :nine) user=> `(abc ~(symbol (str "i" "s" \- "cool")))(user/abc is-cool) user=> `(max ~@(shuffle (range 10)))(clojure.core/max 8 7 1 9 0 6 4 2 3 5)
user=> '(foo bar)(foo bar)user=> `(foo bar)(user/foo user/bar)
user=> (defmacro debug [x] `(println ">>" '~x ":" ~x x))#'user/debuguser=> (let [a 10] (debug a))CompilerException java.lang.RuntimeException: No such var: user/x, compiling:(NO_SOURCE_PATH:72)user=>
我们暂时把x随便换成一个数字23让代码可以执行,可以看到其它部分的代码都是正确的:
user=> (defmacro debug [x] `(println ">>" '~x ":" ~x 23))#'user/debuguser=> (let [a 10] (debug a))>> a : 10 23niluser=>
user=> `'y (quote user/y) 这个是可以理解的,'y等价(quote y),`'y 也就是`(quote y),结果是(quote user/y) 但是``y 的结果和我预期的不一致: user=> ``y (quote user/y) 我想的是`y 的结果是user/y,然后`user/y的结果是user/y,也就是说``y的结果应该是user/y
' 的实现dispatchMacros['\''] = new VarReader(); public static class VarReader extends AFn{ public Object invoke(Object reader, Object quote) { PushbackReader r = (PushbackReader) reader; Object o = read(r, true, null, true); return RT.list(THE_VAR, o); }} `的实现macros['`'] = new SyntaxQuoteReader(); public static class SyntaxQuoteReader extends AFn{ // 代码省略........} ~的实现 macros['~'] = new UnquoteReader(); static class UnquoteReader extends AFn{ public Object invoke(Object reader, Object comma) { PushbackReader r = (PushbackReader) reader; int ch = read1(r); if(ch == -1) throw Util.runtimeException("EOF while reading character"); if(ch == '@') { Object o = read(r, true, null, true); return RT.list(UNQUOTE_SPLICING, o); } else { unread(r, ch); Object o = read(r, true, null, true); return RT.list(UNQUOTE, o); } }}
user=> (let [x 9, y '(- x)] (println 0 y) (println 1 `y) (println 2 ``y) (println 3 ```y) ;(println 4 ~y) (println 5 `~y) (println 6 ``~y) (println 7 ``~~y))0 (- x)1 user/y2 (quote user/y)3 (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (quote user/y))))5 (- x)6 user/y7 (- x)niluser=>
user=> (def x 12)#'user/xuser=> (def y 23)#'user/y user=> `y user/yuser=> ``y (quote user/y)user=> `'y(quote user/y)user=> ```y (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (quote user/y))))user=> ````y(clojure.core/seq (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/y))))))))))))) 下面开始折腾~运算符,首先看到~需要在`的情况下才有效,否则就会有下面这种错误 user=> ~y IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote clojure.lang.Var$Unbound.throwArity (Var.java:43) user=> `~y23user=> `'y(quote user/y)user=> 'yyuser=> `'~y(quote 23)user=> `2323user=> `~~yIllegalStateException Attempting to call unbound fn: #'clojure.core/unquote clojure.lang.Var$Unbound.throwArity (Var.java:43)user=> ``~~y23user=> `~'yyuser=> (= `y 'y)falseuser=> (= y 'y)falseuser=> 'yyuser=> (= 'y (quote y))trueuser=> (quote y)yuser=> ``~~y23user=> ``~yuser/yuser=> `~y23user=> (macexpand-1 ``~~y)CompilerException java.lang.RuntimeException: Unable to resolve symbol: macexpand-1 in this context, compiling:(NO_SOURCE_PATH:133)user=> (macroexpand-1 ``~~y)23user=> `'23(quote 23)user=>
user=> (defmacro ya-defn [fn-name args & body] `(defn ~fn-name ~args (println "Calling ..." ~fn-name ~args) ~@body))#'user/ya-defnuser=> (ya-defn add [a b] (+ a b))#'user/adduser=> (add 2 3)Calling ... #[2 3]5
user=> (macroexpand-1 '(ya-defn add [a b] (+ a b)))(clojure.core/defn add [a b] (clojure.core/println "Calling ..." add [a b]) (+ a b))user=> (pprint (macroexpand-1 '(ya-defn add [a b] (+ a b))))(clojure.core/defnadd[a b](clojure.core/println "Calling ..." add [a b])(+ a b))nil user=> (pprint (macroexpand '(ya-defn add [a b] (+ a b))))(defadd(clojure.core/fn ([a b] (clojure.core/println "Calling ..." add [a b]) (+ a b))))nil
user=> (source macroexpand)(defn macroexpand "Repeatedly calls macroexpand-1 on form until it no longer represents a macro form, then returns it. Note neither macroexpand-1 nor macroexpand expand macros in subforms." {:added "1.0" :static true} [form] (let [ex (macroexpand-1 form)] (if (identical? ex form) form (macroexpand ex))))niluser=> (source macroexpand-1)(defn macroexpand-1 "If form represents a macro form, returns its expansion, else returns form." {:added "1.0" :static true} [form] (. clojure.lang.Compiler (macroexpand1 form)))niluser=>
user=> `(x#)(x__6__auto__) ;;;定义dbguser=> (defmacro dbg[x] `(let [x# ~x] (println '~x "=" x#) x#))#'user/dbguser=> (defn pythag [x,y] (*(* x x) (* y y)))#'user/pythaguser=> (pythag 5 6 )900user=> (defn pythag [x,y] (dbg(* (dbg (* x x)) (dbg (* y y)))))#'user/pythaguser=> (pythag 5 6 )(* x x) = 25(* y y) = 36(* (dbg (* x x)) (dbg (* y y))) = 900900
user=> ( -> 25 Math/sqrt int list)(5)user=> ( ->> 25 Math/sqrt int list)(5)user=> (source ->)(defmacro -> "Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc." {:added "1.0"} ([x] x) ([x form] (if (seq? form) (with-meta `(~(first form) ~x ~@(next form)) (meta form)) (list form x))) ([x form & more] `(-> (-> ~x ~form) ~@more)))niluser=> (source ->>)(defmacro ->> "Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc." {:added "1.1"} ([x form] (if (seq? form) (with-meta `(~(first form) ~@(next form) ~x) (meta form)) (list form x))) ([x form & more] `(->> (->> ~x ~form) ~@more)))niluser=>
转载地址:http://odxax.baihongyu.com/