在Clojure中应用的习惯用法

时间:2013-03-20 14:58:47

标签: clojure

如果这是一个真正基本的问题,我很抱歉,但我见过的一些代码让我很好奇。

apply函数的惯用法是什么?

例如,我见过用以下形式编写的代码:

(distinct [1 2 3 4 5 6])

(apply distinct? [1 2 3 4 5 6])

这些返回相同的结果,甚至在文档中,它清楚地说:

  

;;请注意以下两种形式的等效性

     

用户=> (apply str [“str1”“str2”“str3”])“str1str2str3”

     

用户=> (str“str1”“str2”“str3”)“str1str2str3”

这个例子是否过于基本,无法传达apply的用处?或者我错过了两者之间的根本区别?

什么时候一种形式被认为最好?

4 个答案:

答案 0 :(得分:5)

user=> (apply str ["str1" "str2" "str3"]) "str1str2str3"

user=> (str "str1" "str2" "str3") "str1str2str3"

在此示例中,使用apply的优点是它可以获取字符串列表。 str本身不能。

我不是专家,但我的直觉说除非必要,否则不应使用apply。因此,如果您有一组要传递给可变参数函数的值,apply很有用 - 否则,只需使用普通函数,例如: str

答案 1 :(得分:4)

这些都是正确的,但原因各不相同:

(distinct? [1 2 3 4 5 6])
;=> true

只有一个参数,1..6的向量, 它与任何其他论点截然不同,因为那里 没有其他参数

(apply distinct? [1 2 3 4 5 6])
;=> true

有6个参数,所有参数都是不同的。

观察:

(distinct? [1 1 1])
;=> true

只有一个参数,即三个1 s

的向量
(apply distinct? [1 1 1])
;=> false

有三个参数,其中三个都是1

注意区别:

(str [1 2 3])
;=> "[1 2 3]" -- single argument of a vector stringified

(apply str [1 2 3])
;=> "123" -- three arguments each stringified and concatenated

对转化(apply f [a b c]) => (f a b c)应用效果,通常(f [a b c])相同。

答案 2 :(得分:2)

如果要将集合视为函数的参数,请使用apply。在distinct的情况下,它需要一个集合作为它的参数,因此没有必要使用apply

(distinct [1 2 3 4 1 1])
;returns: (1 2 3 4)
如果

distinct?的参数不同,则返回true:

(distinct? [1 2 3 4 1 1])
;returns true because there's only one argument

apply使用集合中的项作为参数:

(apply distinct? [1 2 3 4 1 1])
;returns false because of the duplicated 1's

答案 3 :(得分:1)

通常,我在调用函数时使用apply将向量转换为参数。这与JavaScript中的apply函数非常相似,如here

所示

str之类的函数是可变参数,并且期望与输入相同的类型,在本例中,是实现toString的任何内容。使用(str a b c)是惯用的,(apply str [a b c])不是。

当您有一个异构向量时,可以使用函数apply,该向量的项目要用作函数的参数。您可能会发现需要创建向量列表,其中向量中的项对应于函数的参数,然后必须使用apply

我认为apply为:将矢量爆炸成参数。

示例:

(def authtypes [:basic :basic :oauth])
(def usernames ["charlie" "snoopy" "lisa"])
(def passwords ["brown" "dog" "maggie"])

(let [credentials (map vector authtypes usernames passwords)]
  (doseq [c credentials]
    (apply login-user c)))