首页 > 解决方案 > Clojure如何使用reducer实现map?

问题描述

我正在阅读七周内的七个并发模型,并且没有关于 Clojure 的先验知识。我很难理解下面的代码,它在集合上实现了 map 函数(可简化)。

我已经将我的具体问题放在代码正文中,但我对代码逻辑更感兴趣。我知道 coll-reduce 是为一堆序列对象定义的,但是在这段代码中如何使用它来实现 map 让我很困惑。

任何提示表示赞赏。

;---
; Excerpted from "Seven Concurrency Models in Seven Weeks",
; published by The Pragmatic Bookshelf.
; Copyrights apply to this code. It may not be used to create training material, 
; courses, books, articles, and the like. Contact us if you are in doubt.
; We make no guarantees that this code is fit for any purpose. 
; Visit http://www.pragmaticprogrammer.com/titles/pb7con for more book information.
;---
(ns reducers.core
  (:require [clojure.core.protocols :refer [CollReduce coll-reduce]]
            [clojure.core.reducers :refer [CollFold coll-fold]]))

(defn make-reducer [reducible transformf]
  (reify
    CollReduce
    (coll-reduce [_ f1]
      (coll-reduce reducible (transformf f1) (f1)))   ; what's the meaning of (f1) here?
    (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))))))

(into [] (my-map (partial * 2) [1 2 3 4]))  ; I don't really understand what's reducef and what's acc here

标签: clojure

解决方案


首先,map、mapcat、filter等都可以用reduce来实现。考虑以下向量 map 的简单实现(使用更详细的名称以增加清晰度):

(defn my-map [mapping-function collection]
  (reduce
    (fn [accumulator element]
      (conj accumulator (mapping-function element)))
    []
    collection))

(println (my-map (partial + 2) [1 2 3])) ; prints [3 4 5]

如果您来自花括号,则大致相当于 Javascript 数组

    function myMap(mappingFunction, collection) {
      return collection.reduce(function(acc, element) {
        acc.push(mappingFunction(element));
        return acc;
      }, []);
    }

据我所知,您发布的版本中所有额外措辞的原因是,它在各种集合类型上具有多态性并且运行速度相当快,而我的极小版本仅适用于向量并且速度很慢。至于您对代码的具体问题:

(coll-reduce reducible (transformf f1) (f1)))   ; what's the meaning of (f1) here?

f1是一个通用的归约函数。

我不太明白这里的 reducef 和 acc 是什么

想想 map-defined-in-terms-of-reduce 做了什么:

  1. 从集合中取出一个项目
  2. 对其执行功能
  3. 将更改后的值添加到新集合(通常是相同类型)。

这里,mapf是我们用来转换集合元素的函数,acc是累加器:正在构建的新集合,reducef是归约函数,负责将转换的输出与累积的新集合一起并将它们连接起来。


推荐阅读