pair:: (cons x y) firstpair -> x secondpair -> y
那么它的具体实现会是这样的
(defn cons [x y]
(fn [m]
(cond (= m 0) x
(= m 1) y)))
(defn first [z]
(z 0))
(defn second [z]
(z 1))
也可以是这样的,还可以是其它各种各样的形式。
(defn cons [x y]
(fn [b]
(b x y))
(defn first [z]
(z (fn [x y] x)))
(defn second [z]
(z (fn [x y] y)))
高阶函数就是可以接收函数的函数,高阶函数提供了足够的抽象,屏蔽了很多底层的实现细节。比如Clojure中的 map 高阶函数,它接收 (fn [v] ...) ,把一组数据映射成另外一组数据。
(map inc [1 2 3 4 5]) ; -> (2 3 4 5 6)
这些函数抽象出映射这样语义,除了容易记忆,还能很方便地重新编写成高效的底层实现。也就是说,一旦出现了更高效的 map 实现算法,现有的代码都能立刻从中受益。
函数组合之后会产生巨大的能量
(((comp (map inc) (filter odd?)) +) 1 2) ; -> 4
怎么去理解这个函数的组合?我们给它取个好听的名字
(def special+ ((comp (map inc) (filter odd?)) +))
(special+ 1 2) ; -> 4
; <=> 等价于
(if (odd? (inc 2))
(+ 1 3))
1)
这个未必是个好的组合方式,但是不可否认的是,我们可以用这些随意地将这些函数组合到一起,得到我们想要的结果。
(def xf (comp (filter odd?) (take 10))) (transduce xf conj (range)) ;; [1 3 5 7 9 11 13 15 17 19]
这里直接将求值延迟到了 transduce 计算的时候,换句话说, xf 定义了一种过程:filter出奇数并取出前10个元素。同等的代码,如果用表达式直接书写的话,如下:
(->> (range)
(filter odd?)
(take 10))
这里的问题就是我们没能使用高阶函数抽象出过程,如果把 conj 换成其他的reduce运算,现在的过程无法支撑,但是tranducers可以!
(transduce xf + (range)) ;-> 100
我们再看一个tranducer的神奇使用方式:
(defn log [& [idx]]
(fn [rf]
(fn
([] (rf))
([result] (rf result))
([result el]
(let [n-step (if idx (str "Step: " idx ". ") "")]
(println (format "%sResult: %s, Item: %s" n-step result el)))
(rf result el)))))
(def ^:dynamic *dbg?* false)
(defn comp* [& xforms]
(apply comp
(if *dbg?*
(->> (range)
(map log)
(interleave xforms))
xforms)))
(binding [*dbg?* true]
(transduce
(comp*
(map inc)
(filter odd?))
+
(range 5))) ;; -> 9
Step: 0. Result: 0, Item: 1
Step: 1. Result: 0, Item: 1
Step: 0. Result: 1, Item: 2
Step: 0. Result: 1, Item: 3
Step: 1. Result: 1, Item: 3
Step: 0. Result: 4, Item: 4
Step: 0. Result: 4, Item: 5
Step: 1. Result: 4, Item: 5
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-83096-5.html
请教授下课吧
应该大力提升女性的经济地位
可是合娶老婆你太恶心我了