为什么 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
我一直在编写一段相当简单的代码来掌握 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