为什么Clojure中没有多个返回值

Las*_*ssi 2 clojure

Clojure中缺少多重回报价值支持的理由是什么?(Clojure似乎与Common Lisp的values/ 相似multiple-value-bind

在函数式编程风格中,显式解构是否被认为更惯用了?它是否与JVM有关,还是仅仅是因为它太复杂而得不到什么收益?

Ala*_*son 5

听起来您已经熟悉使用向量和贴图进行的基本Clojure破坏:

(defn calc-sqr-vec [x]
  [ x  (* x x) ])         ; returns a vector of 2 values

(defn calc-sqr-map [x]
  { :x x  :y (* x x) })   ; returns a map of 2 entries

(let [ [x y] (calc-sqr-vec 3) ]
  (println (format "3^2 -> [%d,%d]" x y)))

(let [ {:keys [x y]} (calc-sqr-map 3) ]
  (println (format "3^2 -> [%d,%d]" x y)))

vec: 3^2 => [3,9]
map: 3^2 => [3,9]
Run Code Online (Sandbox Code Playgroud)

在这里,您将两个返回值x&包裹y单个矢量或映射中,并在需要时调用方提取组件值。

我无法回答与whyCL 有关的部分,但是与Python样式的多个返回值相比,一个很大的好处是当用户未指定所有返回值时该怎么办的问题。例如:

q, r = divmod(22, 7)
q => 3
r => 1

q = divmod(22, 7)
q => (3,1)
Run Code Online (Sandbox Code Playgroud)

因此,在Python中,同一表达式会divmod(22, 7)生成不同的结果,具体取决于语句的“接收”部分。通过始终返回相同的单个值并允许调用者选择何时及如何选择所需位(并忽略不需要的位),可以避免这种复杂性。


更新资料

有趣的是,这个话题今天出现了,因为就在昨天,我正在使用需要返回大量单独值的函数。我写了一个简短的宏以使其更容易。单元测试显示了它的作用:

(dotest
  (let [some-fn (fn []
                  (let [a 1
                        b 2
                        c 3
                        d 4
                        e 5]
                    (label-value-map a b c d e))) ]
    (is= {:a 1 :b 2 :c 3 :d 4 :e 5} (some-fn))
    (let [ {:keys [a b c d e]} (some-fn) ]
      (is= [a b c d e] [1 2 3 4 5]))))
Run Code Online (Sandbox Code Playgroud)

因此,使用label-value-map和传统的{:keys [a b c d e]}解构方法,您可以通过较少的键入将一堆标量值从一个地方转移到另一个地方。:)