如何在本地repl中查看Clojure局部变量?

时间:2018-04-01 15:35:38

标签: clojure binding var read-eval-print-loop

我想通过在函数体中放置一个repl(使用clojure.main / repl)来开发并基于局部变量开发表达式:

(ns something)

(defn myfunc [ p ]
   (let [local (+ p 10)]
        (clojure.main/repl)
        (+ local 100)))

(myfunc 666)

当我执行此操作时,repl启动正常,但函数和本地let-bindings的参数似乎在提示中不可见:

something=> p
CompilerException java.lang.RuntimeException: Unable to resolve symbol: p in this context
something=> local
CompilerException java.lang.RuntimeException: Unable to resolve symbol: local in this context

我已经能够通过创建新的^:dynamic vars并使用绑定在本地设置它们的值来传递值,但这非常复杂,需要为每个局部变量单独绑定:

(def ^:dynamic x)

(defn myfunc [ p ]
   (let [local (+ p 10)]
        (binding [x local]
                 (clojure.main/repl))
        (+ local 100)))

是否有更简单的方法来传递/访问此类本地repl中的本地值?或者是否有更好的方法从非本地repl访问本地变量,例如" lein repl"?

2 个答案:

答案 0 :(得分:0)

使用:init挂钩,可以在REPL命名空间中定义任意变量。

(defn myfunc [p]
  (let [local (+ p 10)]
    (clojure.main/repl :init #(do (def p p) (def local local)))
    (+ local 100)))

这是一个repl宏,可以更容易地添加断点:

(defmacro locals []
  (into {}
        (map (juxt name identity))
        (keys &env)))

(defn defs [vars]
  (doseq [[k v] vars]
    (eval (list 'def (symbol k) (list 'quote v)))))

(defmacro repl []
  `(let [ls# (locals)]
     (clojure.main/repl :init #(defs ls#))))

现在你可以放入(repl)

(defn myfunc [p]
  (let [local (+ p 10)]
    (repl)
    (+ local 100)))

答案 1 :(得分:-1)

我不知道使用repl的好答案,但我赞成使用好的老式打印输出。 spyxlet-spylet-spy-pretty宏促进了这一点:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(defn myfunc [ p ]
  (spyx p)
  (let-spy [local (+ p 10)]
    (+ local 100)))

(dotest
  (spyx (myfunc 666)))

结果:

p              => 666
local          => 676
(myfunc 666)   => 776

关于spyx&的文件朋友is here in the README,还有full API documentation on GitHub pages