文章出處
文章列表
前言
習慣了Ramda.js就會潛意識地認為函數均已柯里化,然后就可以隨心所欲的用函數生成函數,或者使用compose組合多個函數來生成一個新函數。如下
const f = a => b => a + b
const g = c => d => c - d
const compose = f => g => x => f(g(x))
const add1 = f(1)
add1(2) // 返回3
const addThenMinus = compose(g(2), f(1))
addThenMinus(3) // 返回-2
ES6的arrow function讓我們輕易寫出柯里化的函數(當然使用Ramda.js會更輕松),若換成ES5就蛋痛很多了。而不幸的是cljs采納和js一樣能夠接受可變參數的函數特性,這使得其必須拋棄如haskell函數自動柯里化的特性。若用cljs實現上述代碼將會如此地丑陋
(defn f [a]
(fn [b] (+ a b)))
(defn g [c]
(fn [d] (- c d)))
(def add1 (f 1))
那么要如何才能在cljs中優美地實現柯里化呢?答案是兩步走:
- 實現Ramda.js中
R.curry
函數的cljs版 - 借助curry函數實現macro
實現curry函數
;; 定義
(defn curry
[f n & args]
(fn [& more]
(let [a (vec (concat args more))]
(if (> n (count a))
(apply curry (reduce conj [f n] a))
(apply f (take n a))))))
;; 使用
(defn f [a b]
(+ a b))
(def fc (curry f 2))
(def add1 (fc 1))
實現defnc宏
;; 定義
(defmacro defnc [name args & body]
{:pre [(not-any? #{\&} args)]}
(let [n (count args)]
`(def ~name
(curry
(fn ~args ~@body)
~n))))
;; 使用
(defnc f [a b]
(+ a b))
(def add1 (f 1))
總結
cljs中的macro讓我們可以靈活擴展語言特性,真是越用越酸爽啊!
尊重原創,轉載請注明來自:http://www.cnblogs.com/fsjohnhuang/p/7103601.html ^_^肥仔John
文章列表
全站熱搜