gpt4 book ai didi

scala - 如何在 Scala 中实现惰性链模式

转载 作者:行者123 更新时间:2023-12-04 08:39:59 25 4
gpt4 key购买 nike

我正在尝试定义一组“LazyChains”,用于在将来处理传入的消息。我希望 LazyChains 的 API 与 Scala 集合 API(即:Seq、Stream 等)无法区分。这将允许我在消息到达之前提前声明性地定义过滤/转换/操作。这可能是一个众所周知的模式,我不知道它的名字,所以我很难找到任何关于它的结果。

这是我试图完成的一个例子:

val chainA = LazyChain()
.filter(_ > 1)
.map(x => x * 2)
.foreach(println _)

val chainB = LazyChain()
.filter(_ > 5)
.flatMap(x => Seq(x, x))
.foreach(println _)

chainA.apply(2) // should print "4"
chainA.apply(1) // should print nothing
chainB.apply(10) // should print "10" - twice

这种模式是否已经存在于 Scala 集合 API 中?如果没有,我该如何实现这个类 LazyChain ?

这是我目前在这方面的尝试。我似乎无法弄清楚如何让类型工作:
case class LazyChain[I, O](val filter : Option[I => Boolean],
val transform : I => O,
val action : Option[O => Unit]) {

def filter(otherFilter : I => Boolean): LazyChain[I, O] = {
val newFilter = Some({ x : I => {
filter.map(_.apply(x)).getOrElse(true) && otherFilter.apply(x)
}})
copy(filter = newFilter)
}

def map[X](otherTransform : O => X) : LazyChain[I, X] = {
new LazyChain[I, X](
filter = filter,
transform = (x: I) => {
otherTransform.apply(transform.apply(x))
},
/*
type mismatch;
[error] found : Option[O => Unit]
[error] required: Option[X => Unit]
*/
action = action
)
}

def flatMap[X](otherTransform : O => Seq[X]) : LazyChain[I, X] = {
new LazyChain[I, X](
filter = filter,
transform = (x: I) => {
/**
type mismatch;
[error] found : Seq[X]
[error] required: X
*/
otherTransform.apply(transform.apply(x))
}
)
}

def foreach(newAction : O => Unit) = {
copy(action = Some(newAction))
}

def apply(element : I) = {
if (filter.map(_.apply(element)).getOrElse(true)) {
val postTransform = transform.apply(element)
action.foreach(_.apply(postTransform))
}
}
}
object LazyChain {
def apply[X]() : LazyChain[X, X] = {
new LazyChain(filter = None, transform = x => x, action = None)
}
}

最佳答案

你想要的只是包装一个函数 I => List[O]用一些奇特的方法。你可以写你的implicit class将这些方法添加到这种类型,但 Kleisli 通过各种猫类型类免费完成大部分工作,主要是 FilterFunctor .

  import cats.implicits._
import cats.data.Kleisli

type LazyChain[I, O] = Kleisli[List, I, O]
def lazyChain[A]: LazyChain[A, A] = Kleisli[List, A, A](a => List(a))

val chainA = lazyChain[Int]
.filter(_ > 1)
.map(x => x * 2)
.map(println)

val chainB = lazyChain[Int]
.filter(_ > 5)
.flatMapF(x => List(x, x))
.map(println)

chainA(2) // should print "4"
chainA(1) // should print nothing
chainB(10) // should print "10" - twice

它可能看起来有点太神奇了,所以这是一个手工制作的版本:
case class LazyChain[A, B](run: A => List[B]) {

def filter(f: B => Boolean): LazyChain[A, B] = chain(_.filter(f))

def map[C](f: B => C): LazyChain[A, C] = chain(_.map(f))

def flatMap[C](f: B => List[C]): LazyChain[A, C] = chain(_.flatMap(f))

def chain[C](f: List[B] => List[C]): LazyChain[A, C] = LazyChain(run andThen f)
}
object LazyChain {
def apply[I]: LazyChain[I, I] = new LazyChain(a => List(a))
}

链接转换是一个常见的问题,正如评论所说,使用 monix.Observable、iteratees 等是解决这个问题的正确方法(而不是简单的 List 和流自然是懒惰的。

关于scala - 如何在 Scala 中实现惰性链模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54683926/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com