对于我来说,作为一个新的Clojurian,一些核心功能在讨论论点的顺序/位置时似乎有点违背直觉和困惑,下面是一个例子:
> (nthrest (range 10) 5)
=> (5 6 7 8 9)
> (take-last 5 (range 10))
=> (5 6 7 8 9)也许它背后有一些我还没有看到的规则/逻辑?
我不相信Clojure核心团队做出了这么多出色的技术决定,并且忘记了函数命名/参数排序的一致性。
还是我应该只记得它的原样?
谢谢
略微偏离主题:
rand&rand-int与random-sample --另一个函数命名似乎不一致的例子,但这是一个很少使用的函数,所以这不是什么大事。
发布于 2020-03-27 20:34:14
对于某些函数(特别是"seq,seq“),对args进行排序,以便可以按以下方式使用partial:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(dotest
(let [dozen (range 12)
odds-1 (filterv odd? dozen)
filter-odd (partial filterv odd?)
odds-2 (filter-odd dozen) ]
(is= odds-1 odds-2
[1 3 5 7 9 11])))对于其他函数,Clojure通常遵循“最大-优先”或“最重要-优先”的顺序(通常这些排序具有相同的结果)。因此,我们看到的例子如下:
(get <map> <key>)
(get <map> <key> <default-val>)这还表明,根据定义,任何可选值都必须是最后值(以便使用"rest“args)。这在大多数语言(例如Java)中很常见。
说句公道话,我真的不喜欢使用部分函数,因为它们有用户定义的名称(最好是)或者是内联使用(更常见)。请考虑以下代码:
(let [dozen (range 12)
odds (filterv odd? dozen)
evens-1 (mapv (partial + 1) odds)
evens-2 (mapv #(+ 1 %) odds)
add-1 (fn [arg] (+ 1 arg))
evens-3 (mapv add-1 odds)]
(is= evens-1 evens-2 evens-3
[2 4 6 8 10 12]))也是
我个人认为真的很烦人,试图像使用evens-1那样使用partial解析代码,特别是对于用户定义的函数,甚至没有+那么简单的标准函数。
当partial与2个或更多的args一起使用时,情况尤其如此。
evens-2的函数文字对我来说更容易读懂。evens-3所示),或者创建一个常规的(defn some-fn ...)全局函数。发布于 2020-03-27 21:27:04
对于这个问题,Clojure.org有一个常见问题:订单
核心功能中arg顺序的经验法则是什么? 主集合操作数优先。这样,我们就可以编写→及其类似的类,并且它们的位置与它们是否具有可变的参数无关。在面向对象语言和通用Lisp
(slot-value, aref, elt)中有这样的传统。 思考序列的一种方法是从左边读取序列,并从右读取序列: <- 1 2 3 4 大多数序列函数消耗并产生序列。因此,一种形象化的方法是把它看作是一条链: map <-过滤器<- 1 2 3 4 考虑许多seq函数的一种方法是,它们以某种方式被参数化了: (地图f) <- (过滤器预d) <- 1 2 3 4 因此,序列函数将它们的源函数和它们之前的任何其他参数放在最后,而部分函数允许像上面那样直接参数化。在函数式语言和Lisps中有这样的传统。 注意,这与最后取主操作数是不一样的。一些序列函数有多个源(级联、交织)。当序列函数是可变的,它通常是在它们的来源。 改编自Rich的评论。
发布于 2020-03-27 21:04:42
使用seqs的函数通常使用实际的seq作为最后一个参数。(地图、过滤器、遥控器等)
访问和“更改”单个元素将集合作为第一个元素: conj、assoc、get、update。
这样,您就可以使用具有一致性的集合的(->>)宏,以及一致地创建转换器。
只有很少有人不得不求助于(as->)来改变参数顺序。如果您必须这样做,这可能是一个检查您自己的功能是否遵循该约定的机会。
https://stackoverflow.com/questions/60893605
复制相似问题