虽然我同意 Josh 的观点,您可能不应该在生产环境中运行它,但我认为在 repl 中使用它作为一种便利并没有什么害处(事实上,我认为我会将它复制到我的调试中 - repl 厨房水槽库)。
我喜欢编写宏(尽管通常不需要它们),所以我编写了一个实现。它接受任何绑定形式,例如let。
(我先写了这个规范,但是如果你使用的是 clojure
(ns macro-fun
(:require
[clojure.spec.alpha :as s]
[clojure.core.specs.alpha :as core-specs]))
(s/fdef syms-in-binding
:args (s/cat :b ::core-specs/binding-form)
:ret (s/coll-of simple-symbol? :kind vector?))
(defn syms-in-binding
"Returns a vector of all symbols in a binding form."
[b]
(letfn [(step [acc coll]
(reduce (fn [acc x]
(cond (coll? x) (step acc x)
(symbol? x) (conj acc x)
:else acc))
acc, coll))]
(if (symbol? b) [b] (step [] b))))
(s/fdef defs
:args (s/cat :binding ::core-specs/binding-form, :body any?))
(defmacro defs
"Like def, but can take a binding form instead of a symbol to
destructure the results of the body.
Doesn't support docstrings or other metadata."
[binding body]
`(let [~binding ~body]
~@(for [sym (syms-in-binding binding)]
`(def ~sym ~sym))))
;; Usage
(defs {:keys [foo bar]} {:foo 42 :bar 36})
foo ;=> 42
bar ;=> 36
(defs [a b [c d]] [1 2 [3 4]])
[a b c d] ;=> [1 2 3 4]
(defs baz 42)
baz ;=> 42
关于您的 REPL 驱动开发评论:
我对 Ipython 没有任何经验,但我会简要解释一下我的 REPL 工作流程,您也许可以评论与 Ipython 的任何比较/对比。
我从来没有像终端一样使用我的 repl,输入命令并等待回复。我的编辑器支持(emacs,但任何 clojure 编辑器都应该这样做)将光标放在任何 s 表达式的末尾并将其发送到 repl,在光标之后“打印”结果。
我通常在我开始工作的文件中有一个comment 块,只需输入任何内容并对其进行评估。然后,当我对结果相当满意时,我将其从“repl-area”中拉出并进入“real-code”。
(ns stuff.core)
;; Real code is here.
;; I make sure that this part always basically works,
;; ie. doesn't blow up when I evaluate the whole file
(defn foo-fn [x]
,,,)
(comment
;; Random experiments.
;; I usually delete this when I'm done with a coding session,
;; but I copy some forms into tests.
;; Sometimes I leave it for posterity though,
;; if I think it explains something well.
(def some-data [,,,])
;; Trying out foo-fn, maybe copy this into a test when I'm done.
(foo-fn some-data)
;; Half-finished other stuff.
(defn bar-fn [x] ,,,)
(keys 42) ; I wonder what happens if...
)
您可以在clojure core source code 中查看此示例。