为什么 Clojure 在进入 REPL 时会接受它,但在编写为函数时却不会?

Why will Clojure accept this when entered into a REPL, but not when written as a function?

我一直在编写一段相当简单的代码来掌握 Clojure 的窍门,但我 运行 遇到了一个问题,当我按顺序将每一行传递到 REPL 时(使用测试用例时)替换将作为函数的一部分传递的值),我得到了预期的结果,但是当我尝试将其编译为函数时,出现错误 Execution error (ClassCastException) at testenv.core/sum-of-two-largest-squares (core.clj:14). class clojure.lang.PersistentList cannot be cast to class clojure.lang.IFn (clojure.lang.PersistentList and clojure.lang.IFn are in unnamed module of loader 'app') 相关函数如下(注意我把每一步都移到了变量中,以便找出问题所在)

(defn sum-of-two-largest-squares [a b c]
     (
      (def x (into () (map math/abs [a b c])))
      (def m (apply min x))
      (def y (into () (map square (remove (fn [n] (= n m)) x))))
      (apply + y)
     )
)

你不能只是在事物周围加上括号而不期望它会改变含义。

REPL 中 运行 时有效的是:

(defn abs [n] (java.lang.Math/abs n))
(defn square [n] (* n n))

(def x (into () (map abs [a b c])))
(def m (apply min x))
(def y (into () (map square (remove (fn [n] (= n m)) x))))
(apply + y)

...和strictly,如果注入到一个函数中,这仍然有效,只要你去掉额外的括号(尽管它工作缓慢并且由于不需要的副作用不当使用 def):

(defn sum-of-two-largest-squares [a b c]
  (def x (into () (map abs [a b c])))
  (def m (apply min x))
  (def y (into () (map square (remove (fn [n] (= n m)) x))))
  (apply + y)
)
(sum-of-two-largest-squares a b c)

但是,良好做法 替代方案将使用 let

(defn abs [n] (java.lang.Math/abs n))
(defn square [n] (* n n))

(defn sum-of-two-largest-squares [a b c]
     (let [x (into () (map abs [a b c]))
           m (apply min x)
           y (into () (map square (remove (fn [n] (= n m)) x)))]
       (apply + y)))

下面是这个问题比较典型的解决方法

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

(defn square [x] (* x x))
(defn sum-of-two-largest-squares [a b c]
  (let-spy
    [sorted      (sort [a b c])
     largest-two (rest sorted)
     squares     (mapv square largest-two)
     result      (apply + squares)]
    result))

(dotest
  (is= 41 (spyx (sum-of-two-largest-squares 3 4 5)))
  )

结果:

-----------------------------------
   Clojure 1.10.3    Java 15.0.2
-----------------------------------

Testing tst.demo.core
sorted => (3 4 5)
largest-two => (4 5)
squares => [16 25]
result => 41
(sum-of-two-largest-squares 3 4 5) =>  41

Ran 2 tests containing 0 assertions.
0 failures, 0 errors.

它使用my favorite template project。完成 writing/debugging.

后,只需将 let-spy 改回 let