Я хочу поэкспериментировать и разработать выражения на основе локальных переменных, поместив repl (с помощью clojure.main / repl) внутри тела функции:
(ns something)
(defn myfunc [ p ]
(let [local (+ p 10)]
(clojure.main/repl)
(+ local 100)))
(myfunc 666)
Когда я выполнил это, ответ запускается нормально, но параметры функции и локальные привязки let не отображаются в приглашении:
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
Мне удалось передать значения, создав новые динамические переменные ^: и установив их значения локально с привязкой, но это довольно сложно и требует отдельной привязки для каждой локальной переменной:
(def ^:dynamic x)
(defn myfunc [ p ]
(let [local (+ p 10)]
(binding [x local]
(clojure.main/repl))
(+ local 100)))
Есть ли более простой способ передать / получить доступ к локальным значениям в таком локальном ответе? Или есть лучший способ получить доступ к локальным переменным из нелокального repl, например, "lein repl"?
Спасибо,: init выглядит многообещающим. В документации говорится: «: init, функция без аргументов, инициализация, вызываемая с привязками для set! -Able переменных на месте». Но я не смог найти с помощью некоторого поиска в Google ни одного примера, как использовать: init для передачи значений, вы можете предоставить его?





Я не знаю хорошего ответа на вопрос, но я предпочитаю использовать старые добрые распечатки. Этому способствуют макросы spyx, let-spy и let-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 и друзьям здесь в README, есть еще полная документация по API на страницах GitHub.
Спасибо за шпионскую информацию! Это определенно может быть хорошим инструментом в моем наборе инструментов для отладки. Я все еще продолжаю искать способ использовать repl на месте, так как я в основном использую это для облегчения разработки новых выражений, основанных на существующих значениях (а не просто просматривая существующие значения)
Используя ловушку :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)))
Эта функция defs неверна. Попробуйте это с локальным адресом, значением которого является список (1 2 3): он попытается вызвать 1 как функцию. Вы должны хотя бы указать значение: (eval (list 'def (symbol k) (list 'quote v))).
Вы можете использовать ловушку
replfn:initдля определения переменных.