haw*_*eye 8 scala clojure transducer transducer-machines
Paul Chiusano和RúnarÓli 在Scala编写了一本精彩的函数编程书.在其中他们提到了Scala社区中一个有点引用的概念 - Transducers.

我的问题是:Scala Transducers**之间有什么相同点和不同点(来自Scala中的函数编程一书)和Clojure Transducers?**
假设:
我知道
来自Scala函数编程(FPiS)和Clojure传感器的流传感器非常相似.它们是使用"机器"(步骤函数)将输入流处理成输出流的概念的概括.FPiS的传感器称为Processes.Rich Hickey 在他关于Clojure传感器的介绍性演讲中也使用了术语过程.
FPiS传感器的设计基于Mealy机器.据说Mealy机器有:
transition function T : (S, I) -> S
output function G : (S, I) -> O
Run Code Online (Sandbox Code Playgroud)
这些功能可以融合在一起形成:
step: (S, I) -> (S, O)
Run Code Online (Sandbox Code Playgroud)
接下来很容易看出,步进功能对机器的当前状态和下一个输入项进行操作,以产生机器和输出项的下一个状态.
FPiS的组合器之一使用这样的阶梯函数:
trait Process[I, O] {
...
def loop[S, I, O](z: S)(f: (I,S) => (O,S)): Process[I, O]
...
}
Run Code Online (Sandbox Code Playgroud)
这个loop功能基本上是Rickey 在本幻灯片中谈到的种子左侧缩减.
两者都可以在许多不同的上下文中使用(例如列表,流,通道等).
在FPiS传感器中,过程类型是:
trait Process[I, O]
Run Code Online (Sandbox Code Playgroud)
所有它知道的是它的输入元素和它的输出元素.
在Clojure中,这是一个类似的故事.希基称之为"完全脱钩".
两种类型的换能器都可以组成.
FPiS使用"管道"操作符
map(labelHeavy) |> filter(_.nonFood)
Run Code Online (Sandbox Code Playgroud)
Clojure使用 comp
(comp
(filtering non-food?)
(mapping label-heavy))
Run Code Online (Sandbox Code Playgroud)
在Clojure中:
reducer: (whatever, input) -> whatever
transducer: reducer -> reducer
Run Code Online (Sandbox Code Playgroud)
在FPiS中:
// The main type is
trait Process[I, O]
// Many combinators have the type
Process[I, O] ? Process[I, O]
Run Code Online (Sandbox Code Playgroud)
然而,FPiS的代表不仅仅是一个功能.它是一个案例类(代数数据类型),有3种变体:Await,Emit和Halt.
case class Await[I,O](recv: Option[I] => Process[I,O])
case class Emit[I,O](head: O, tail: Process[I,O]
case class Halt[I,O]() extends Process[I,O]
Run Code Online (Sandbox Code Playgroud)
reducedClojure 的角色.两者都支持提前终止.Clojure使用一个reduced可以通过reduced?谓词测试的特殊值来完成它.
FPiS使用更静态类型的方法,进程可以处于以下3种状态之一:Await,Emit或Halt.当"步进函数"返回状态Halt的过程时,处理函数知道停止.
在某些方面,他们又是相似的.两种类型的传感器都是需求驱动的,不会产生中间集合.但是,我想象FPiS的换能器在流水线/组合时效率不高,因为内部表示不仅仅是"只是一堆函数调用",正如Hickey所说的那样.我只是在这里猜测效率/性能.
考虑fs2(先前scalaz-stream)针对基于在FPiS换能器的设计也许更高性能库.
以下是filter两种实现中的示例:
Clojure,来自Hickey的谈话幻灯片:
(defn filter
([pred]
(fn [rf]
(fn
([] (rf))
([result] (rf result))
([result input]
(if (prod input)
(rf result input)
result)))))
([pred coll]
(sequence (filter red) coll)))
Run Code Online (Sandbox Code Playgroud)
在FPiS中,这是实现它的一种方法:
def filter[I](f: I ? Boolean): Process[I, I] =
await(i ? if (f(i)) emit(i, filter(f))
else filter(f))
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,它filter是由其他组合器构建的,例如await和emit.
在实施Clojure传感器时,有许多地方需要小心.这似乎是一种有利于提高效率的设计权衡.然而,这种下行似乎主要影响图书馆的生产者,而不是最终用户/消费者.
reduced从嵌套步进调用中获取值,则它必须永远不会再使用输入调用该步骤函数.FPiS的传感器设计有利于正确性和易用性.管道组成和flatMap操作确保完成操作立即发生并且错误得到适当处理.这些问题不是传感器实现者的负担.也就是说,我想这个库可能没有Clojure那么高效.
Clojure和FPiS传感器都具有:
它们的基本表现略有不同.Clojure型换能器似乎有利于效率,而FPiS换能器有利于正确性和组合性.
| 归档时间: |
|
| 查看次数: |
940 次 |
| 最近记录: |