我一直在用另一种语言重新实现一些 Clojure 函数,使用测试作为参考,我对clojure.core/comp
测试有点困惑。
(deftest test-comp
(let [c0 (comp)]
(are [x] (= (identity x) (c0 x))
nil
42
[1 2 3]
#{}
:foo)
(are [x y] (= (identity x) (c0 y))
(+ 1 2 3) 6
(keyword "foo") :foo)))
comp
本身只使用一次,没有参数。该行为似乎没有记录在案,但源代码显示它只返回identity
函数。
(defn comp
([] identity)
([f] f)
([f g]
(fn
([] (f (g)))
([x] (f (g x)))
([x y] (f (g x y)))
([x y z] (f (g x y z)))
([x y z & args] (f (apply g x y z args)))))
([f g & fs]
(reduce1 comp (list* f g fs))))
这是否意味着这些 3/4 的 arities 没有经过测试?还是在其他地方保存了测试?我通过GitHub搜索找到了这些测试,它们并不总是完全可靠的。
为什么零 arity 形式有测试,而它似乎是最无用的变体?
- 是的。它只在这里进行测试。事实上,在 v1.3.0 中添加零参数版本之前,没有对
comp
进行测试。检查此提交及其父提交。 - 零参数
comp
很有用,它有助于消除极端情况下的琐碎分支代码。假设您要对给定输入进行一系列转换。但这些转换是动态生成的,它可能会降级到不应执行任何转换的程度。
编辑:举个关于我的观点2的例子:
(defn my-format
"Returns an HTML representation of the given text in a paragraph,
supports `:b' for bold and `:i' for italic font, and possibly more
in the future."
[text & more-args]
(let [wrap (fn [w t] (str "<" w ">" t "</" w ">"))]
(wrap "p" ((apply comp
(map #(partial wrap (name %)) more-args))
text)))
; => (my-format "hello world" :b :i)
; "<p><b><i>hello world</i></b></p>
; => (my-format "hello world")
; "<p>hello world</p>
代码片段是微不足道的,但你明白了。如果comp
不支持 0-arity 版本,代码看起来就不会那么优雅。