編輯:
多虧了@amalloy建議,在這裏是不使用的「嚴重錯誤」 eval
,包括一些小型試驗一些改進宏:
(import 'java.lang.ArithmeticException)
(defmacro explain-expr
"Produce a string representation of the unevaluated expression x, concatenated to
an arrow and a string representation of the result of evaluating x, including
Exceptions should they arise."
[x]
`(str ~(str x) " ~~> "
(try ~x (catch Exception e# (str e#)))))
(println (explain-expr (* 42 42)))
(println (explain-expr (let [x 1] x)))
(println (explain-expr (/ 6 0)))
(println (let [x 1] (explain-expr x)))
(let [y 37] (println (explain-expr (let [x 19] (* x y)))))
(let [y 37] (println (explain-expr (let [y 19] (* y y)))))
(* 42 42) ~~> 1764
(let [x 1] x) ~~> 1
(/ 6 0) ~~> java.lang.ArithmeticException: Divide by zero
x ~~> 1
(let [x 19] (* x y)) ~~> 703
(let [y 19] (* y y)) ~~> 361
(defmacro explain-exprs
"Produce string representations of the unevaluated expressions xs, concatenated
to arrows and string representations of the results of evaluating each
expression, including Exceptions should they arise."
[& xs]
(into [] (map (fn [x]
`(str ~(str x) " ~~> "
(try ~x (catch Exception e# (str e#)))))
xs)))
(clojure.pprint/pprint
(let [y 37]
(explain-exprs
(* 42 42)
(let [x 19] (* x y))
(let [y 19] (* y y))
(* y y)
(/ 6 0))))
["(* 42 42) ~~> 1764"
"(let [x 19] (* x y)) ~~> 703"
"(let [y 19] (* y y)) ~~> 361"
"(* y y) ~~> 1369"
"(/ 6 0) ~~> java.lang.ArithmeticException: Divide by zero"]
(defmacro explanation-map
"Produce a hashmap from string representations of the unevaluated expressions
exprs to the results of evaluating each expression in exprs, including
Exceptions should they arise."
[& exprs]
(into {}
(map (fn [expr]
`[~(str expr)
(try ~expr (catch Exception e# (str e#)))])
exprs)))
(clojure.pprint/pprint
(let [y 37]
(explanation-map
(* 42 42)
(let [x 19] (* x y))
(let [y 19] (* y y))
(* y y)
(/ 6 0))))
{"(* 42 42)" 1764,
"(let [x 19] (* x y))" 703,
"(let [y 19] (* y y))" 361,
"(* y y)" 1369,
"(/ 6 0)" "java.lang.ArithmeticException: Divide by zero"}
棄用:
我在離開這個作爲什麼不做一個說明。
這裏有一個變化,將在任何類型的表達式的工作(我認爲)
(defmacro dump-strings-and-values
"Produces parallel vectors of printable dump strings and values. A dump string
shows an expression, unevaluated, then a funny arrow, then the value of the
expression."
[& xs]
`(apply map vector ;; transpose
(for [x# '~xs
v# [(try (eval x#) (catch Exception e# (str e#)))]]
[(str x# " ~~> " v#) v#])))
(defmacro pdump
"Print dump strings for one or more given expressions by side effect; return
the value of the last actual argument."
[& xs]
`(let [[ss# vs#]
(dump-strings-and-values [email protected])]
(clojure.pprint/pprint ss#)
(last vs#))
一些樣本:
(pdump (* 6 7))
打印["(* 6 7) ~~> 42"]
並返回42
。
(pdump (* 7 6) (/ 1 0) (into {} [[:a 1]]))
打印
["(* 7 6) ~~> 42"
"(/ 1 0) ~~> java.lang.ArithmeticException: Divide by zero"
"(into {} [[:a 1]]) ~~> {:a 1}"]
,並返回{:a 1}
。
編輯:
我試圖在打印輸出擺脫了外括號,即
(defmacro vdump
"Print dump strings for one or more given expressions by side effect; return
the value of the last actual argument."
[& xs]
`(let [[ss# vs#]
(dump-strings-and-values [email protected])]
(map clojure.pprint/pprint ss#)
(last vs#)))
確實不工作,我不知道爲什麼。它不打印輸出,但宏觀擴展看起來不錯。可能是nREPL或REPL問題,但是我只是使用了上面的那個,不用擔心括號太多。
完美!謝謝! –