是否有简单的方法可以忽略不必要的参数?
例如:
(#(+ %1 %2) 1 2)
返回3
我想强制使用此代码
(#(+ %1 %2) 1 2 3)
也返回3。但它返回
java.lang.IllegalArgumentException:传递的args(3)数量错误 到。
如何更改#(+ %1 %2)
?
我希望有比#(+ (nth %& 0) (nth %& 1))
更优雅的方式。
答案 0 :(得分:18)
以下是我要使用的内容:
=> ((fn [a b & _] (+ a b)) 1 2 3)
=> 3
这会创建一个匿名函数,它接受任意数量的参数,但只添加前两个参数。 _
符号没有做任何特别的事情,它只是惯用于“我不关心这件事,但我需要它以某种方式绑定”。如果你认为你将要做很多事情,那么你可能想要定义它:
(defn add-first-two
[a b & _]
(+ a b))
如果您真的使用#()
语法,则必须在定义中的某处包含%&
以“实现”它应该采用任意数量的参数。这并不意味着您必须在显示时将其编入索引,它只需要出现某处。这是一个例子:
=> (#(do %& (+ %1 %2)) 1 2 3)
=> 3
另一方面,这个解决方案涉及%&
的某种处理,你不需要任何处理,可能稍微放慢速度(我不确定)这个,也许别人可以给我反馈意见)。一个相当有趣的解决方案是将%&
粘贴到(comment ...)
块中,该块将评估为nil
。
=> (#(do (comment %&) (+ %1 %2)) 1 2 3)
=> 3
更奇特的解决方案是使用#_...
,这与(comment...)
非常相似,只是读者实际将其从评估中删除,就好像你只是在那里输入任何东西一样。这样,也许我们可以将它粘贴在(+ ...)
的主体内以缩短代码。
=> (#(+ %1 %2 #_%&) 1 2 3)
=> 3
你知道什么,它有效。我以前从未尝试过这个,我很惊讶它看起来有用。显然,在#_...
部分被删除之前有一些处理。奇怪。
如果您不喜欢这些奇怪的评论解决方案,并且do
没有为您执行此操作,您可以随时将其放在(if nil ...)
块中:
=> (#(if nil %& (+ %1 %2)) 1 2 3)
=> 3
嗯,毕竟,我仍然最喜欢第一个解决方案(使用(fn ...)
),但其中一些肯定是更短。
答案 1 :(得分:5)
这适用于任意数量的参数,并且可读:
(fn [& args] (apply + args))
如果您只想使用前两个参数(根据Alex的评论):
(fn [& args] (apply + (take 2 args)))
您可以直接使用它:
((fn [& args] (apply + (take 2 args))) 1 2)
; => 3
或者将函数绑定到这样的符号:
(let [f (fn [& args] (apply + (take 2 args)))]
(f 1 2))
; => 3
或创建一个var:
(def f (fn [& args] (apply + (take 2 args))))
或功能:
(defn f [& args] (apply + (take 2 args)))
最佳定义取决于您的使用案例。
答案 2 :(得分:4)
(#(apply + (take 2 %&)) 1 2 3 4 5)
;; => 3
答案 3 :(得分:1)
user> (#(do %& (+ % %2)) 1 2)
3
user> (#(do %& (+ % %2)) 1 2 3)
3
它不是很优雅,但我认为这是可以接受的。