有没有适配器可以使函数忽略多余的参数?

4

我正在寻找一个Clojure函数,我们称之为anyargs,它允许其函数参数忽略多余的参数。例如:

((anyargs cons) :a [:b :c] :d) ; => (:a :b :c)

如果函数参数有多个不同的形式,最好选择最适合的那个。
3个回答

4
一种方法是检查该函数需要多少个参数。 这个链接 讲述了如何检测它。如果您略微修改该答案,则可以得到最大参数数量:
(defn n-args [f]
  (-> f class .getDeclaredMethods last .getParameterTypes alength))

只有在方法数组按参数长度排序时,此方法才有效,在我的系统上似乎是这种情况。如果您确实想要确保,请使用以下代码:
(defn n-args [f]
  (apply max
        (map #(-> % .getParameterTypes alength)
             (-> f class .getDeclaredMethods))))

然后你可以写下这些内容:
(defn anyargs [f]
    (let [n (n-args f)]
        (fn [& args] (apply f (take n args)))))

这个方法使用了反射,但是对于可变参数函数会出现问题,但是假设你不会在可变参数函数上使用它。除了提供一个包装器来捕获ArityExceptions并一次又一次地尝试减少参数直到其正常工作之外,这是我目前能想到的最好的方法。

1
由于Clojure没有通过公共API暴露其函数的arity,因此它不够干净。
鉴于您必须知道要应用的函数的arity,在特定情况下实现这一点非常容易,其中n是arity。
#(apply f (take n %&))

1

我认为你需要黑客攻击它。

(defn max-arities [f] 
  (reduce 
    #(merge-with max % {(.getName %2) (alength (.getParameterTypes %2))})
    {} 
    (seq (.getDeclaredMethods (class +)))))


(defn anyargs [f] 
  (let [accept (if (instance? clojure.lang.RestFn f) 
                 identity 
                 (partial take ((max-arities f) "invoke")))] 
    (fn [& args] (apply f (accept args)))))


((anyargs cons) :a [:b :c] :d) ;=> (:a :b :c)
((anyargs +) 1 2 3 4 5 6 7 8 9 10) ;=> 55

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接