繁体   English   中英

Scala Cats或Scalaz类型类scanLeft之类

[英]Scala Cats or Scalaz typeclass scanLeft like

我想知道在CatsScalaz中是否有typeclass提供这样的运算符:

def scan[G[_],A,B](zero: B)(g: G[A],f: (A,B) => B):G[B]

或者,如果存在这样的运算符的某种数学定义(类似于Monad for bind/flatMap )。

这个typeclass的想法是将二进制函数应用于类型构造函数并获取相同类型的构造函数,但使用不同的类型参数(二进制函数返回的相同类型)。

我认为类似于scanLeft的Scala标准库集合。

可能的实施之一是与State进行traverse

import cats._, data._, implicits._

def scan[G[_]: Traverse: Applicative: MonoidK, A, B](list: G[A], zero: B, f: (B, A) => B): G[B] = {
  def generate(a: A): State[B, B] =
    for {
      prev <- State.get[B]
      next =  f(prev, a)
      _    <- State.set(next)
    } yield next

  zero.pure[G] <+> list.traverse(generate).runA(zero).value
}

这类似于stdlib中的scanLeft for Vectors和Lists(但不是选项!),但需要相当多的类型类! 不幸的是,stdlib scanLeft设置初始元素,因此结果集合总是比原始元素大一个元素,并且没有单个类型类提供任何类似的操作。

如果你没有预先设置zero ,你在G[_]上需要的只是Traverse ,这不是一半坏。 如果你不是,你可能最好使用子类型进行泛化

回答原来的问题,不,我不认为已经有这样的类型类。 但是,您可以使用Foldable实现类似的功能。

使用猫:

import cats.data.NonEmptyList
import cats.Foldable

implicit class ScanLeftable[F[_], T](val ts: F[T]) extends AnyVal {
  def scanLeft2[U](zero: U)(f: (U, T) => U)
                  (implicit fo: Foldable[F]): NonEmptyList[U] = {
    Foldable[F].foldLeft(ts, NonEmptyList.of(zero)) { (lu, t) =>
      f(lu.head, t) :: lu
    }.reverse
  }
}

import cats.instances.list._
val z = List(5, 10).scanLeft2(0)((a, b) => a + b)
println(z == NonEmptyList.of(0, 5, 15)) //true

您可能会尝试使其在返回类型方面更通用,或者返回像Iterator这样的惰性结构。 但是,如果不引入新的类型类,我不确定它是多么通用。

编辑:该方法严格scanLeft2以便我可以确定没有调用标准库。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM