Function 在Clojure中传递方法名称以进行评估的惯用方法?
我正在传递一个函数的名称,以便在另一个方法中使用Function 在Clojure中传递方法名称以进行评估的惯用方法?,function,hash,clojure,lisp,idioms,Function,Hash,Clojure,Lisp,Idioms,我正在传递一个函数的名称,以便在另一个方法中使用 (defn mapper [m function] (cond (= '() m) '() true (cons (function (first m)) (mapper (rest m) function)))) (println (mapper '((blue red)(green red)(white red)) #'first)) 在clojure中有没有更惯用的方法来实现这一点?我相信你的方法
(defn mapper [m function]
(cond
(= '() m) '()
true (cons (function (first m))
(mapper (rest m) function))))
(println (mapper '((blue red)(green red)(white red)) #'first))
在clojure中有没有更惯用的方法来实现这一点?我相信你的方法基本上是惯用的。Clojure自己的
map
使用:
(defn mapper [coll f]
(when-let [s (seq coll)]
(cons (f (first s)) (mapper (rest s) f))))
我已经严重缩短了它-原始生成一个延迟序列,处理多个集合,分块序列,等等。顺便说一下-我假设您想要传递的是实际的函数,而不是它的名称
coll
和f
分别是表示集合和函数的惯用arg名称 我觉得你的版本不错。您将在clojure代码库中看到的常用名称是集合的“coll”。我还看过哈斯克尔风格的“xs”。您也可以参考有关各种约定的说明
回到例子:两个观察结果
user> (defn mapper [coll f]
(cond
(not (seq coll)) nil
:else (conj (mapper (next coll) f)
(f (first coll)))))
#'user/mapper
user> (mapper '(1 2 3) #(* % %))
(1 4 9)
user> (mapper [1 2 3] #(* % %))
(1 4 9)
注意,就集合而言,conj做的是“正确的事情”。它将新元素添加到列表的头部、向量的尾部等等。还要注意在传统的lisp中使用了“next”而不是first/restnext'返回第一个元素之后的元素序列。因此,可以通过对集合进行排序来检查空值,对于空列表或空向量,该集合将返回nil。这样,它适用于所有系列。- 更喜欢向量而不是列表。在大多数情况下,您不必引用向量,而且它在很多方面都有更好的性能,比如随机访问。列表在Clojure中的使用要比在其他Lisp中少得多
- 喜欢关键字而不是引用符号。关键字突出显示为“常量字符串”或枚举值。Clojure中的关键字可以属于名称空间,因此它们具有符号的所有优点。再说一次,没有必要引用关键字,这很好。引用符号在Clojure中很少使用,除非您正在编写宏
是名为“first”的变量#“first
是称为“first”的风险值,即fn。在这种情况下,first
和(#'first foo)
给出相同的答案,但是(first foo)
每次调用时都会进行额外的解引用。所以不要这样做,除非你想让这种去引用一次又一次地发生。通常不需要使用#'first
#'
- 内置的
是惰性的,而您的则不是。内置的map
利用分块seq获得更好的性能,而您的没有。惯用代码不必是惰性的或使用分块的seq,但请记住,内置代码具有一些这种魔力。所以好好利用一下map
- 空seq的惯用测试不是
,而是(='()x)
,如果(seq x)
为空,则返回x
。请注意,在Clojure中,nil
为false(='()nil)
- 如果您确实需要使用空列表(您很少需要这样做),您不必引用它。只需使用
()
- 内置的
首先接受函数参数,因为它接受多个集合参数。当函数接受多个参数时,这些参数在参数列表中必须排在最后。我认为另一种方式读起来也更好:“(mapfcoll):在这个集合中映射这个函数”map
- 如果只有两个选项,则无需使用
。如果,则可以使用cond
。如果
中的一个分支返回if
,则可以在nil
时使用
。在适当的时候使用
和
如果
是很好的,因为它们会立即向读者传达你的意图,而
可以做任何事情,迫使读者阅读更多cond
user> (mapper first [[:blue :red] [:green :red] [:white :red]])
(:blue :green :white)
我想最惯用的方法是使用函数:
(map first'((蓝红色)(绿红色)(白红色))
。同意翻转参数。或者(defn mapper[coll f&args]…)
,其中args
作为附加的args传递给f,这样就可以实现(mapper[5 2 3]+1)
之类的功能。