clojure 编辑器_学习Clojure:换能器

clojure 编辑器

本周,主题是换能器。 但是在进入该主题之前,我们首先需要更多地讨论减速器。

这是在学习Clojure的焦点series.Other职位包括8 职位:

  1. 解码Clojure代码,让您不知所措
  2. 学习Clojure:应对动态打字
  3. 学习Clojure:arrow和doto宏
  4. 学习Clojure:动态调度
  5. 学习Clojure:依赖类型和基于合同的编程
  6. 学习Clojure:与Java流进行比较
  7. 关于学习Clojure的反馈:与Java流进行比较
  8. 学习Clojure:换能器 (本文)

Java减少

如果您有Java 8的经验,您可能已经了解Stream.reduce()函数。 提供三种不同的口味:

  1. Optional<T> reduce(BinaryOperator<T> accumulator)
  2. T reduce(T identity, BinaryOperator<T> accumulator)
  3. <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)

用法示例如下:

int[]ints=newint[]{0,1,2,3,4};
OptionalIntsum1=Arrays.stream(ints).reduce(Integer::sum); (1)
intsum2=Arrays.stream(ints).reduce(0,Integer::sum); (2)
  1. 没有初始值,得出10
  2. 初始值也为10

注意,第一风味剂和第二风味剂之间的唯一区别是初始值的存在。 这意味着,第二香味被绑定到返回一个值, 即使该流不包含任何元素 ,即 OptionalInt VS int

第三种口味的唯一用例是并行处理,因此我们将其放在一边。

减少Kotlin

Kotlin中的还原与Java中的还原非常相似。 开箱即用提供了两种简化功能:

  1. 一个没有初始值的文件,名为reduce()
  2. 另一个具有初始值,称为fold()
valints=arrayOf(0,1,2,3,4)
valsum1=ints.reduce(Int::plus)
valsum2=ints.fold(0,Int::plus)

返回不相关的类型

实际上,Java和Kotlin的缩减都非常有限:返回的类型表示单个值。 减少(也称为倍数)的定义要广泛得多:

在函数式编程中,折叠(也称为减少,累加,聚集,压缩或注入)是指一系列高阶函数,这些函数分析递归数据结构,并通过使用给定的组合运算来重组递归处理其结果的结果。组成部分,建立回报价值。 通常,折叠具有组合功能,数据结构的顶部节点以及可能在某些条件下使用的某些默认值。 折叠然后继续以系统的方式使用功能组合数据结构层次结构的元素。

—折叠(高阶功能)
https://zh.wikipedia.org/wiki/Fold_(高级功能)

此定义对结果类型没有任何要求。 由于集合的类型与其他类型相同,因此以下功能也有所减少:

funreduce(acc:Set<Int>,ints:List<Int>):Set<Int>=acc+ints
funreduce(acc:Set<Int>,aInt:Int):Set<Int>=acc+aInt
funreduce(aInt:Int):Set<Int>=setOf(aInt)
funreduce(ints:List<Int>):Set<Int>=setOf<Int>()+ints

归纳归约

在这个阶段,下一步是很小的。 让我们考虑以下代码:

ints.distinct()

这与上面的最后一个功能相同。 考虑到更广泛的定义, distinct()也是归约函数。

同样,以下两个代码段相同:

funreduce(ints:List<Int>):List<Int>{
    vallist=mutableListOf<Int>()
    ints.forEach{list.add(it+1)}
    returnlist
}

ints.map{it+1}

因此, map()是归约函数。 filter()符合定义。 更多功能也符合上面的描述。

换能器

现在已经正确定义了归约函数,现在可以定义换能器是什么:

换能器(有时称为xformxf )是从一种归约函数到另一种归约函数的转换

—术语
https://clojure.org/reference/transducers

归约函数的组成与此相符。 现在已经定义了换能器,现在该是Clojure了。 实际上,Clojure使定义换能器变得容易。

让我们从使用thread-last宏定义归约函数管道开始:

(defn transform [coll]
  (->> coll             (1)
    (filter even?)      (2)
    (take 5)            (3)
    (map inc)))         (4)

提醒一下,这是分步说明:

  1. coll开始-假设一组数字
  2. 仅保留偶数
  3. 仅保留前5个数字
  4. 每个数字加一

组成功能

下一步是使用允许组成函数的(comp)函数:

(comp)(comp f)(comp fg)(comp fg & fs)

接受一组函数并返回一个由这些fns组成的fn。 返回的fn采用可变数量的args,将fns的最右边应用于args,将下一个fn(从右至左)应用于结果,依此类推。

— ClojureDocs
https://clojuredocs.org/clojure.core/comp

为了从管道创建合成函数,使用(comp)函数。

(def transducer
  (comp
    (filter even?)
    (take 5)
    (map inc)))

创建换能器

重要的一点是,尽管(transform)(transducer)函数实现看起来相同,但它们却不同。

在thread-last的上下文中, ->> ,该函数在“管道”点处应用于结果集合。

(--> (range 25)
  (filter even?)
  (take 5)
  (map inc))

例如,在上面的代码片段中, (filter even?)函数应用于(range 25)函数的结果。 如关于线程宏文章中所见,这与(filter even? (range 25))

相反,在(transducer)函数的上下文中, (filter even?)使用单个参数执行(filter)函数。 回到(filter)的定义:

(filter pred)(filter pred coll)

返回coll中项目的惰性序列, (pred item)为其返回逻辑truepred必须没有副作用。 没有提供任何收集时返回一个传感器。

— ClojureDocs
https://clojuredocs.org/clojure.core/filter

使用REPL可以很容易地验证最近的要求:

(filter even?)

=> #object[clojure.core$filter$fn__5610 0x261832c7 " [email protected] "]

实际上,在不提供任何集合的情况下,许多处理集合的现成的Clojure函数也会返回一个换能器。 这不仅包括到目前为止使用的功能(filter)(take)(map) ,还包括:

  • (distinct)
  • (drop)
  • (map-indexed)
  • (mapcat)
  • (partition-by)
  • (random-sample)
  • (remove)
  • 等等

要点中提供了核心中提供的换能器的详尽列表。

应用换能器

要将换能器应用于集合,Clojure提供了(transduce)功能:

(transduce xform f coll)(transduce xform f init coll)

f (xf)的变换来减少。 如果未提供init ,则将调用(f)生成它。 f应该是一个接受1和2参数的归约步骤函数,如果它仅接受2,则可以将arity-1添加为'completing'。 返回将(转换后的) xf应用于init和coll中的第一项的结果,然后将xf应用于该结果和第二项,以此类推。

— ClojureDocs
https://clojuredocs.org/clojure.core/transduce

由于形式上的定义可能有点让人不知所措,因此以下是使用(transducer)的示例:

(transduce
  (take 5)      (1)
  conj          (2)
  (range 25))   (3)
  1. 创建一个采用前5个元素的换能器
  2. (take 5 (range 25))简化为向量
  3. 初始集合

与最后线程宏相比,有两个重要区别:

  1. 换能器是高阶函数 它可用作参数和返回值。
  2. (transducer)需要一个附加参数,并允许第二个参数。 必选参数是归约函数,而可选参数是初始值。

结论

使用换能器,可以定义一个命名的折减管道。 它们允许独立于任何源或目标来定义转换或转换的有序管道。

但是,换能器远不止于此:有无状态换能器和有状态换能器。 同样, (transduce)只是在Clojure中应用换能器的一种方法,但还有其他方法。

这只是换能器的第一步。

更进一步:

翻译自: https://blog.frankel.ch/learning-clojure/7/

clojure 编辑器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值