Zipper to iterate over list in Scala

爷,独闯天下 提交于 2019-11-30 01:26:46

问题


This is a follow-up to my previous question. I can use an iterator, fold, zip, foreach and others to iterate over a list in Scala. Now I wonder if there are use cases where Zipper is most appropriate. Suppose I need read-only access without concurrency.

Could you give such an example and explain why the Zipper is the best choice?


回答1:


One of the many neat things about zippers is that they have a comonad instance, which allows us to solve a certain class of problems very elegantly.

Here's a quick example off the top of my head. Suppose that we've got a sequence of numbers and we want to do a simple form of smoothing with an exponential moving average, where the new value for each position in the list is an average of the current value and all the other values, but with more distant neighbors contributing less.

This isn't a terribly hard thing to compute imperatively, but if we use a zipper and a comonadic cobind it's not too far from a one-liner:

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
}

Now if we write:

val result = smooth(NonEmptyList[Double](0, 0, 0, 1, 0, 0, 0)).toList

We'll get the moral equivalent of:

List(1 / 24, 1 / 12, 1 / 6, 1 / 3, 1 / 6, 1 / 12, 1 / 24)

Which is what we want, given how we defined the problem.



来源:https://stackoverflow.com/questions/23984160/zipper-to-iterate-over-list-in-scala

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!