Scala map2 在元组上与内部幺半群(或者:如何做这个简单的事情但更好?



情况:

事件流(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

但这把向量踢出了可观察的......

编辑:我想我真正的问题是为什么这种元组的幺半群实例还不存在,或者如果存在,使用它的语法是什么,以便我可以幺半地附加向量元组而不做最后一步幺半附加向量本身?

相关内容

最新更新