これは私の前の質問へのフォローアップです。イテレータ、、、などを使用してfold
、zip
Scalaforeach
のリストを反復処理できます。Zipper
が最も適切なユースケースがあるのではないかと思います。同時実行のない読み取り専用アクセスが必要だとします。
そのような例を挙げて、なぜそれZipper
が最良の選択なのか説明していただけますか?
ジッパーの優れた点の 1 つは、ジッパーに comonad インスタンスがあることです。これにより、特定のクラスの問題を非常にエレガントに解決できます。
これが私の頭の上からの簡単な例です。一連の数値があり、リスト内の各位置の新しい値が現在の値と他のすべての値の平均である指数移動平均を使用して単純な形式の平滑化を行いたいとしますが、遠く離れた隣人は貢献度が低くなります。
これは命令的に計算するのはそれほど難しいことではありませんが、zipper と 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
}
ここで、次のように記述します。
val result = smooth(NonEmptyList[Double](0, 0, 0, 1, 0, 0, 0)).toList
道徳的には次のようになります。
List(1 / 24, 1 / 12, 1 / 6, 1 / 3, 1 / 6, 1 / 12, 1 / 24)
問題をどのように定義したかを考えると、これが私たちが望むものです。