Zipper迭代Scala中的列表

Mic*_*ael 13 scala zipper

这是我上一个问题的后续行动.我可以用一个迭代器,fold,zip,foreach和别人遍历Scala中的一个列表.现在我想知道是否有Zipper最合适的用例.假设我需要没有并发的只读访问权限.

你能举一个这样的例子来解释为什么这Zipper是最好的选择吗?

Tra*_*own 17

拉链的许多巧妙之处在于它们有一个comonad实例,它允许我们非常优雅地解决某类问题.

这是我头脑中的一个快速示例.假设我们有一系列数字,我们希望用指数移动平均线做一个简单的平滑形式,其中列表中每个位置的新值是当前值和所有其他值的平均值,但是与更远的邻居贡献更少.

这绝对不是一件非常难以计算的事情,但如果我们使用拉链和一个comonadic cobind,那么它与单线程的距离并不太远:

import scalaz._, Scalaz._

val weights = Stream.from(1).map(1.0 / math.pow(2, _))

def sumNeighborWeights(neighbors: Stream[Double]) =
  neighbors.fzipWith(weights)(_ * _).sum

def smooth(data: NonEmptyList[Double]) = data.toZipper.cobind { z =>
  (z.focus + sumNeighborWeights(z.lefts) + sumNeighborWeights(z.rights)) / 3
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我们写:

val result = smooth(NonEmptyList[Double](0, 0, 0, 1, 0, 0, 0)).toList
Run Code Online (Sandbox Code Playgroud)

我们将得到道德等同于:

List(1 / 24, 1 / 12, 1 / 6, 1 / 3, 1 / 6, 1 / 12, 1 / 24)
Run Code Online (Sandbox Code Playgroud)

考虑到我们如何定义问题,这就是我们想要的.