Clojure成语:明智地传递函数 - 值对

时间:2014-03-30 19:12:12

标签: clojure

有时我想将参数值对传递给高阶函数,其中我应该传递的值由我传递的参数决定。我希望能够在不明确指定附带值的情况下传递参数。特别是,我对参数本身就是一个函数的情况感兴趣。

通用示例:

这是一个非常通用的示例,其中my-foomy-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使:option13higher-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;这样的电话。

注意:我知道有两种方法可以做到这一点,而且就我个人而言,我认为它们都有效。但我对社区中惯用或被认为是最佳实践感兴趣。我会发布我的答案,但我希望有更多的解决方案。

3 个答案:

答案 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)