I want to play around and develop expressions based on local variables by placing a repl (with clojure.main/repl) inside a function body:
(ns something)
(defn myfunc [ p ]
(let [local (+ p 10)]
(clojure.main/repl)
(+ local 100)))
(myfunc 666)
When I executed this, the repl starts ok, but the parameters of the function and local let-bindings do not seem to be visible in the prompt:
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
I have been able to pass the values by creating new ^:dynamic vars and setting their values locally with binding, but this is quite complex and requires separate binding for each local variable:
(def ^:dynamic x)
(defn myfunc [ p ]
(let [local (+ p 10)]
(binding [x local]
(clojure.main/repl))
(+ local 100)))
Is there simpler way to pass/access local values in such local repl? Or is there some better way to do access the local variables from non-local repl, such as the "lein repl"?
Using the :init
hook, you can define arbitrary vars in the REPL namespace.
(defn myfunc [p]
(let [local (+ p 10)]
(clojure.main/repl :init #(do (def p p) (def local local)))
(+ local 100)))
Here's a repl
macro to make adding a breakpoint easier:
(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#))))
Now you can just drop in (repl)
:
(defn myfunc [p]
(let [local (+ p 10)]
(repl)
(+ local 100)))