情况:
事件流(RxScala(,我们使用tumblingBuffer((对其进行批处理,然后构建完整的历史记录以进行调试。 最终,我希望这些值在所有值的(Seq[T],Seq[T](中,所以我创建了以下函数作为foldLeft的累加器:
def tupleConcat[S](a: (Seq[S], Seq[S]), b: (Seq[S], Seq[S])) = (a._1 ++ b._1, a._2 ++ b._2)
现在,在阅读了 Runar & Paul 的 Scala 函数式编程后,这对我来说引发了一堆警钟,因为这看起来很像两个幺半群实例的 map2,但我仍然有点坚持如何正确概括它。到目前为止,我认为它可能看起来像这样:
def tupleConcatSG[S](a: (S,S), b: (S,S))(implicit s: Semigroup[S]) = (a._1 |+| b._1, a._2 |+| b._2)
(但我必须从我能收集到的信息中将我的 Seq 提升为 IndexedSeq(。
为了进一步推广到任何应用,我想我需要一个元组的实例,它可能来自 Shapeless? 还是我错过了一些明显的东西?
编辑:我还应该补充一点,基于偏见的性能问题,我试图避免压缩和解压缩,但也许我不应该担心这一点...... (每个翻滚缓冲区的 (Seq,Seq( 值为 ~15,000 长,最终值 (Seq,Seq( 应以百万为单位(。
元组部分已经存在;在最坏的情况下,你将需要无形状的scalaz。您的tupleConcatSG
很好(您可以使用: Semigroup
糖而不是显式隐式(,但是如果您希望能够使用|+|
则需要使其成为Semigroup
实例,并且隐式可用:
implicit def tupleConcatSg[S: Semigroup] = new Semigroup[(S, S)] {
def append(f1: (S, S), f2: (S, S)) = ...
}
我怀疑你在这里的真正问题是 scalaz 没有任何用于Seq
的实例,仅用于IndexedSeq
- 请参阅为什么列表是半群而 Seq 不是?. 但是,如果您不担心在 List
上使用 Seq
的++
的性能影响,您可以轻松编写自己的Monoid[Seq]
:
implicit object SeqMonoid extends Monoid[Seq]{...}
我不确定你的意思是进一步推广到任何应用——我们已经很笼统了。如果您谈论的是获取Applicative
实例,例如 List[Writer[Vector[String], A]]
Applicative
的组合,这应该会自动发生。
按照lmm的回答,这真的是我想做的吗? (类型检查出来,我从 Seq 切换到 IndexedSeq 以确保我们可以正确使用 ++(。
def tupleConcatMonoid[M: Monoid] = new Monoid[(M, M)] {
def zero: (M,M) = (Monoid[M].zero, Monoid[M].zero)
def append(f1: (M, M), f2: (M, M)) = (f1._1 |+| f2._1, f2._1 |+| f2._2)
}
val isdMonoid= tupleConcatMonoid[IndexedSeq[Double]]
val history = tumbledBuffers.foldLeft(isdMonoid.zero)(isdMonoid.append)
这有所有正确的类型,但我对"魔法"的水平不是 100% 有信心。 我试图做一个
tumbledBuffers.suml
但这把向量踢出了可观察的......
编辑:我想我真正的问题是为什么这种元组的幺半群实例还不存在,或者如果存在,使用它的语法是什么,以便我可以幺半地附加向量元组而不做最后一步幺半附加向量本身?