Clojure中的高阶函数

Clojure真棒,我们都知道,但这不是重点。 我想知道以类似Haskell的方式创build和pipe理高阶函数的惯用方法是什么。 在Clojure中,我可以执行以下操作:

(defn sum [ab] (+ ab)) 

但是(sum 1)不会返回一个函数:它会导致一个错误。 当然,你可以做这样的事情:

 (defn sum ([a] (partial + a)) ([ab] (+ ab))) 

在这种情况下:

 user=> (sum 1) #<core$partial$fn__3678 clojure.core$partial$fn__3678@1acaf0ed> user=> ((sum 1) 2) 3 

但它似乎不是正确的方式进行。 有任何想法吗?
我不是在讨论实现sum函数,而是在更高的抽象层次上进行交stream。 有没有任何习惯模式? 一些macros? 定义一个macros的最好方法还是有其他解决scheme吗?

有人已经在Clojure小组上实现了这一点 。 你可以指定一个函数有多less个参数,它会为你自己粘贴,直到它得到很多。

在Clojure中,默认情况下不会发生的原因是我们更喜欢可变参数函数来自动执行curry函数。

我已经玩了一下amalloybuild议的function。 我不喜欢明确规定要争论的论点数量。 所以我创build了我的自定义macros。 这是特定高阶函数的旧方法:

 (defn-decorated old-sum [(curry* 3)] [abc] (+ abc)) 

这是我的新macros:

 (defmacro defn-ho [fn-name & defn-stuff] (let [number-of-args (count (first defn-stuff))] `(defn-decorated ~fn-name [(curry* ~number-of-args)] ~@defn-stuff))) 

这是新的隐含的方式:

 (defn-ho new-sum [abc] (+ abc)) 

正如你所看到的,没有(咖喱)和其他东西的痕迹,只是像以前一样定义你的currified函数。

伙计们,你怎么看? 想法? build议? 再见!

Alfedo

编辑:我已经修改macros关于docstring的amalloy问题。 这是更新的版本:

 (defmacro defhigh "Like the original defn-decorated, but the number of argument to curry on is implicit." [fn-name & defn-stuff] (let [[fst snd] (take 2 defn-stuff) num-of-args (if (string? fst) (count snd) (count fst))] `(defn-decorated ~fn-name [(curry* ~num-of-args)] ~@defn-stuff))) 

我不喜欢第二个绑定中的if语句。 任何想法使它更加succint?

这将允许你做你想做的事情:

 (defn curry ([f len] (curry f len [])) ([f len applied] (fn [& more] (let [args (concat applied (if (= 0 (count more)) [nil] more))] (if (< (count args) len) (curry f len args) (apply f args)))))) 

以下是如何使用它:

 (def add (curry + 2)) ; read: curry plus to 2 positions ((add 10) 1) ; => 11 

带有[nil]的条件是为了确保每个应用程序都能确保咖喱状态的一些进展。 背后有一个很长的解释,但我发现它很有用。 如果你不喜欢这一点,你可以设置参数为:

 [args (concat applied more)] 

与JavaScript不同,我们无法知道传递函数的参数,所以您必须指定期望的长度。 这在Clojure [脚本]中有很多意义,其中一个函数可能有多个元素。

Interesting Posts