Scala map2与元组内部的元组(或者:如何做这个简单的事情,但更好?)

时间:2014-12-15 20:32:21

标签: scala scalaz shapeless

情况:

事件的流(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)应该是数百万。)

2 个答案:

答案 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实例不存在,或者如果它存在,为什么使用它的语法是什么,以便我可以单独附加向量元组没有做单独附加载体本身的最后一步?