Programming Clojure学习笔记——函数编程

5.3 进一步延迟
通过组合已有的序列函数,可以找到不需要显式序列的更加延迟的办法。
举例说明,解决如下问题:
统计硬币投掷结果序列中,连续两次出现正面的次数,其中:h表示正面,:t表示反面。如:
[:h :t :t :h :h :h]
第4、5连续两次,第5、6连续两次,一共出现2次

第一种计算方法:
使用loop/recur实现方式:
(defn count-heads-pairs [coll]
    (loop [cnt 0 coll coll]
         (if (empty? coll)
             cnt
            (recur (if (= :h (first coll) (second coll)) (inc cnt) cnt)
        (rest coll)))))
user=> (count-heads-pairs [:h :h :h :t :h]) #返回 2

这种方法虽然能计算出正确的结果,但是语义上不是很明确,不好理解。该问题针对序列[:h :t :t :h :h :h],实际上是要计算每个元素及其邻居是否都是:h,可以将该序列转换为
[[:h :t] [:t :t] [:t :h] [:h :h] [:h :h]],计算其中元素都是:h的对的个数。可以通过如下函数进行转换:
(defn by-pairs [coll]
    (let [take-pair (fn [c] (when (next c) (take 2 c)))]
        (lazy-seq
            (when-let [pair (seq (take-pair coll))]
            (cons pair (by-pairs (rest coll)))))))
也可以通过Clojure提供的函数partition来实现转换:
(partition size step? coll)
按size大小分割集合coll,step默认为size. 如:
user=> (partition 2 1 [:h :t :t :h :h :h])
((:h :t) (:t :t) (:t :h) (:h :h) (:h :h))
user=> (by-pairs [:h :t :t :h :h :h])
((:h :t) (:t :t) (:t :h) (:h :h) (:h :h))

另一个改进是使用count/filter组合计算,定义函数count-if封装这两者的组合:
(use '[clojure.contrib.def :only (defvar)])
(defvar count-if (comp count filter) "Count items matching a filter")
其中comp用来组合两个及两个以上函数:
(comp f & fs)
组合后的函数是一个新函数,它将参数传入最右边函数,然后将计算结果传入倒数第二最右的函数,依次类推。

第二种计算方法:
(defn count-runs
    "Count runs of length n where pred is true in coll."
    [n pred coll]
    (count-if #(every? pred %) (partition n 1 coll)))
user=> (count-runs 2 #(= % :h) [:h :t :t :h :h :h]) #返回 2
还可以很方便的利用该函数计算反面连续出现两次的次数:
user=> (count-runs 2 #(= % :t) [:h :t :t :h :h :h]) #返回 1

利用partial可以创建一个新版本的count-heads-pairs函数:
(defvar count-heads-pairs (partial count-runs 2 #(= % :h))
     "Count runs of length two that are both heads")
其中partial函数
(partial f & partial-args)
执行函数的部分应用,指定要执行的函数f和部分参数列表,剩余参数在partial创建的函数执行时再指定。如上例中
(partial count-runs 2 #(= % :h))
只保留了函数count-runs需要的前两个参数,等同于
(fn [coll] (count-runs 2 #(= % :h) coll))

Curry和Partial应用
当curry一个函数时,得到一个新函数,该函数带一个参数并返回原函数其中那个参数固定。Clojure中没有curry函数。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值