有时我想将参数值对传递给高阶函数,其中我应该传递的值由我传递的参数决定。我希望能够在不明确指定附带值的情况下传递参数。特别是,我对参数本身就是一个函数的情况感兴趣。
通用示例:
这是一个非常通用的示例,其中my-foo
和my-bar
是我传递给higher-foo
的函数:
(higher-foo my-foo :option4 args) ;good
(higher-foo my-bar :option13 args) ;good
(higher-foo my-foo :option13 args) ;how stupid are you?! my-foo requires :option4!
问题:是否有"标准" :option4
使:option13
或higher-foo
可以传播的方法,以便我可以写(higher-foo my-foo)
和(higher-foo my-bar)
?
更具体的例子:
请记住有better alternatives to the following code,但我只想提出一个我所谈论的具体例子:
(defn seq-has? [f n someseq]
(every? (partial apply f)
(partition n 1 someseq)))
(defn monotonicity [a b]
(<= a b))
(defn generalized-fib [a b c]
(= c (+ a b)))
如果序列是单调的,则 (seq-has? monotonicity 2 someseq)
应返回true,否则返回false。如果序列遵循广义Fibonacci形式,(seq-has? generalized-fib 3 someseq)
应返回true,否则返回false。
但&#34; 2&#34;和&#34; 3&#34;来烦我。我可以有任意数量的属性来测试,我不想要记住适当的&#34;魔术数字&#34;这样的电话。
注意:我知道有两种方法可以做到这一点,而且就我个人而言,我认为它们都有效。但我对社区中惯用或被认为是最佳实践感兴趣。我会发布我的答案,但我希望有更多的解决方案。
答案 0 :(得分:4)
只需使谓词函数本身采用可变参数,并让它进行分区/重复。你的单调?例如,已经存在于核心中,并被称为<=
(<= 1 2 4 5)
=> true
(<= 1 2 1 5)
=> false
以下是1,2和可变参数arg版本的来源:
(source <=)
(defn <=
"Returns non-nil if nums are in monotonically non-decreasing order,
otherwise false."
{:inline (fn [x y] `(. clojure.lang.Numbers (lte ~x ~y)))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (. clojure.lang.Numbers (lte x y)))
([x y & more]
(if (<= x y)
(if (next more)
(recur y (first more) (next more))
(<= y (first more)))
false)))
你可以制造一个?以同样的方式工作,让它采用可变参数并重复三元组:
(defn fib?
[a b & [c & r]]
(if (= c (+ a b))
(if r
(recur b c r)
true)
false))
(fib? 0 1 1)
=> true
(fib? 2 3 5 8 13)
=> true
答案 1 :(得分:2)
因为您要求标准方式函数如何从一个参数确定未传递的参数:
(defn f
([arg0] (case a :foo (f a :bar)
:baz (f a :quux)))
([arg0 arg1] ...))
根据您的使用情况,与case
不同的调度结构可能更适合。
对于您的通用示例,这意味着higher-foo
应该在所需的重载中确定正确的:option
,如上所示。
在您的特定示例中,您无法从传递的函数中确定n
。您需要更具体的数据结构:
(defn seq-has? [{:keys [f n]} s]
(every? (partial apply f)
(partition n 1 s)))
(def monotonicity
{:f <=
:n 2})
(def generalized-fib
{:f #(= (+ %1 %2) %3)
:n 3})
(seq-has? monotonicity [1 2 3])
;; => true
答案 2 :(得分:-1)
这个解决方案对我来说似乎是一个黑客攻击。它被认为是常见/惯用吗?在定义您要查找的属性的函数上使用元数据:
(defn higher-foo [foo & args]
(apply foo (:option (meta foo))
args))
(def my-foo
(with-meta
(fn [a b] (println "I'm doing something cool"))
{:option :option4}))
;using it:
user=> (higher-foo my-foo arg)