关于clojure CollReduce协议的问题

最近在看七周七并发模型,现在第三章第三节化简器卡住了,没有函数式编程经验。作者这一章使用了coljure这门语言来实现map reduce并发模型。具体实现的时候用到了clojure的协议,源代码如下(去掉了无关的代码):

(ns reducers.core
  (:require [clojure.core.protocols :refer [CollReduce coll-reduce]]
            [clojure.core.reducers :refer [CollFold coll-fold]]))

(defn my-reduce
  ([f coll] (coll-reduce coll f))
  ([f init coll] (coll-reduce coll f init)))

(defn make-reducer [reducible transformf]
  (reify
    CollReduce
    (coll-reduce [_ f1]
      (coll-reduce reducible (transformf f1) (f1)))
    (coll-reduce [_ f1 init]
      (coll-reduce reducible (transformf f1) init))))

(defn my-map [mapf reducible]
  (make-reducer reducible
    (fn [reducef]
      (fn [acc v]
        (reducef acc (mapf v))))))

这里我有几个不是很明白的地方
一、是这个coljure协议本身,以上面的my-reduce为例,书里的例子是这样的:

reducers.core => (my-reduce + [1 2 3 4])
10

书里说coljure协议跟java的接口很像,所以这里的应该是[]这个数据结构本身实现了CollReduce协议吗?
二、是这个复杂的my-map和make-reduce的实现,这里的make-reducer实现了coll-reduce协议,是否是使用了递归?说实话这个实现我是头雾水,完全不明白是怎么工作的。
三、这里咨询一下读过这本书的大佬,是否需要先简单学习一下Clojure?我看作者后面很多章节也使用了Coljure

阅读 3.6k
1 个回答

没有看过这本书。从代码来看,试试看回答这个问题:

  1. 协议 protocol 是一种 Java 接口,但它额外的能力是可以动态被已知类扩展,而不需要静态实现。my-reduce 函数的实现说明 PersistentVector ([]) 扩展过 CollReduce 协议。
  2. make-reducer 函数倒并不复杂,它简单地委托(delegate)了 CollReduce 协议实现给参数 reducible(也就是说 reducible 是满足 CollReduce协议的)。它的有趣之处是用 transformf 参数(这应该是一个 transducer 函数)来对函数f1 包装,从而让 make-reducer 支持了 transducer 函数。注意 my-map 的实现完全是简化过的 clojure.core 中的 map 函数,它其实不算复杂,是 transducer 函数的标准写法,但其参数栈的定义次序是有奥秘的,具体解释起来就太长,需要理解 transducer 的设计思路。另外,引用的代码应该本身是试图解释 transducer 的设计实现,因此答案就在你的书中。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进