11

有没有简单的方法来忽略不必要的争论?

例如: (#(+ %1 %2) 1 2)返回 3

我想强制执行此代码

(#(+ %1 %2) 1 2 3)

也返回 3。但它返回

java.lang.IllegalArgumentException:传递给的 args (3) 数量错误。

如何改变#(+ %1 %2)

我希望有一些比#(+ (nth %& 0) (nth %& 1)).

4

4 回答 4

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 ...)),但其中一些肯定更短

于 2012-08-02T13:12:50.463 回答
5

这适用于任意数量的参数,并且是可读的:

(fn [& args] (apply + args))

如果您只想使用前 2 个参数(根据 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

或者创建一个变量:

(def f (fn [& args] (apply + (take 2 args))))

或者一个函数:

(defn f [& args] (apply + (take 2 args)))

最佳定义取决于您的用例。

于 2012-08-02T12:22:27.337 回答
4

这个怎么样?

(#(apply + (take 2 %&)) 1 2 3 4 5)
;; => 3
于 2012-08-02T13:58:20.397 回答
1
user> (#(do %& (+ % %2)) 1 2)
3
user> (#(do %& (+ % %2)) 1 2 3)
3

它不是很优雅,但我认为这是可以接受的。

于 2012-08-02T13:09:33.963 回答