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 [脚本]中有很多意义,其中一个函数可能有多个元素。