情况:
事件的流(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& amp;保罗在Scala中的函数式编程,因为它看起来非常像两个monoid实例的map2,但我仍然有点坚持如何正确地推广它。到目前为止,我认为它可能看起来像:
def tupleConcatSG[S](a: (S,S), b: (S,S))(implicit s: Semigroup[S]) = (a._1 |+| b._1, a._2 |+| b._2)
(但我必须从我可以收集的东西中将我的Seq推广到IndexedSeq。)
为了进一步推广任何Applicative,我想我需要一个元组实例,它可能来自Shapeless?还是我错过了一些明显的东西?
编辑:我还应该补充一点,我试图避免拉链和解压缩,基于偏见的性能问题,但也许我不应该担心...(每个翻滚的缓冲区值得(Seq,Seq)将是〜15,000长,最后(Seq,Seq)应该是数百万。)答案 0 :(得分:6)
元组部分已经存在;在最坏的情况下,你将需要无形scalaz。您的tupleConcatSG
很好(您可以使用: Semigroup
糖而不是明确隐含的),但如果您希望能够使用|+|
,则需要将其设为Semigroup
1}}实例,隐式可用:
implicit def tupleConcatSg[S: Semigroup] = new Semigroup[(S, S)] {
def append(f1: (S, S), f2: (S, S)) = ...
}
我怀疑你的真正问题是scalaz没有Seq
的任何实例,仅适用于IndexedSeq
- 请参阅Why is List a Semigroup but Seq is not?。但是,如果您不担心在Monoid[Seq]
上使用Seq
++
的性能影响,您可以轻松编写自己的List
:
implicit object SeqMonoid extends Monoid[Seq]{...}
我不确定你对任何申请人的进一步概括是什么意思 - 我们已经相当普遍了。如果您正在谈论获得Applicative
Applicative
List[Writer[Vector[String], A]]
组合的{{1}}个实例,那么这应该会自动发生。
答案 1 :(得分:1)
接下来回答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
但是,这些载体从Observable中被踢出......
编辑:我猜我真正的问题是为什么这种元组的monoid实例不存在,或者如果它存在,为什么使用它的语法是什么,以便我可以单独附加向量元组没有做单独附加载体本身的最后一步?