Clojure 核心函数参数位置似乎相当混乱。它背后的逻辑是什么?

Nik*_*hev 1 lisp clojure clojurescript clojure-core

对我来说,一个新的 Clojurian,当涉及到参数顺序/位置时,一些核心函数似乎相当违反直觉和令人困惑,这是一个例子:

> (nthrest (range 10) 5) 
=> (5 6 7 8 9)

> (take-last 5 (range 10)) 
=> (5 6 7 8 9)
Run Code Online (Sandbox Code Playgroud)

也许它背后有一些我还没有看到的规则/逻辑?

我拒绝相信 Clojure 核心团队做出了如此多出色的技术决策,却忘记了函数命名/参数排序的一致性。

还是我应该记住它的原样?

谢谢


有点题外话:

rand& rand-intVS random-sample- 另一个例子,函数命名似乎不一致,但这是一个很少使用的函数,所以没什么大不了的。

and*_*hut 7

Clojure.org 上有一个关于这个问题的常见问题解答:https ://clojure.org/guides/faq#arg_order

核心函数中 arg 顺序的经验法则是什么?

主要集合操作数在前。这样一个人可以写?及其同类,它们的位置与它们是否具有可变的参数无关。在 OO 语言和 Common Lisp 中有这样的传统(slot-value, aref, elt)

考虑序列的一种方法是从左侧读取它们并从右侧馈送它们:

<- [1 2 3 4]
Run Code Online (Sandbox Code Playgroud)

大多数序列函数消耗和产生序列。因此,将其可视化的一种方法是作为一个链:

map <- filter <- [1 2 3 4]
Run Code Online (Sandbox Code Playgroud)

考虑许多 seq 函数的一种方法是它们以某种方式参数化:

(map f) <- (filter pred) <- [1 2 3 4]
Run Code Online (Sandbox Code Playgroud)

因此,序列函数最后获取它们的源,以及它们之前的任何其他参数,并且部分允许如上所述的直接参数化。在函数式语言和 Lisps 中有这样的传统。

请注意,这与最后取主操作数不同。一些序列函数有多个源(concat、interleave)。当序列函数是可变参数时,通常在它们的源中。

改编自Rich Hickey 的评论


Joc*_*fer 5

使用 seqs 的函数通常将实际的 seq 作为最后一个参数。(地图、过滤器、远程等)

访问和“更改”单个元素将集合作为第一个元素:conj、assoc、get、update

这样,您可以(->>)一致地将宏与集合一起使用,并一致地创建转换器。

很少有人不得不求助于(as->)改变参数顺序。如果您必须这样做,这可能是检查您自己的函数是否遵循该约定的机会。