gpt4 book ai didi

scala - 不同类型任务的功能组合 - Scala

转载 作者:行者123 更新时间:2023-12-02 00:54:45 25 4
gpt4 key购买 nike

目前,我正在设计一个在 Scala 中构建通用管道的设计(纯粹用于学习目的)。为此,我从一个基本构造 Task 开始,它接受一些 TaskConfiguration(现在,我们可以假设这个 TaskConfiguration 是一个特定于 Task 功能的案例类)。性状结构如下:

trait Task[T <: TaskConfiguration] {
type Out

def taskConfiguration: T
def execute(previousOutput: Option[Out]): Option[Out]
}

要求:1. 我可以有多个扩展任务特征的任务。比如,ReadTask、WriteTask 等,2. 每个任务都有自己的“out”类型

我的问题是:给定一个 List[Task],我如何编写要执行的方法调用。尝试了多种方法来组合它们,但我一直遇到无法区分先前任务结束和当前任务结束的问题,因为我只有一个类型成员来指定此任务可以处理的内容。

我希望我们可以用 Scala 解决这个问题。但考虑到我对使用 Scala 进行函数式编程还很陌生,所以我无法弄明白。非常感谢您。

注意:这个问题的描述可能看起来有点断章取义。但这是目前我能想到的最好的。如果您认为我们可以做得更好,请随意编辑它。如果您认为这个问题没有任何意义,请在评论中提出您的想法,以便我解决。

最佳答案

您可以使用类似于 andThen 的模式来自 Scala 的函数。

我编译了一个小例子:


import scala.util.{Try, Success, Failure}

type TaskConfiguration = Any

trait Task[-C <: TaskConfiguration, +O <: TaskConfiguration] {

def execute(configuration: C): Option[O]

def andThen[O2 <: TaskConfiguration](secondTask: Task[O, O2]): Task[C, O2] = {
val firstTask = this

new Task[C, O2] {
def execute(configuration: C): Option[O2] =
firstTask.execute(configuration).flatMap(secondTask.execute(_))
}
}
}

// From here on it's the example!

case class UnparsedNumber(value: String)

trait ParsedNumber {
val value: Int
}

case class ParsedPositiveNumber(int: Int) extends ParsedNumber {
val value: Int = int
}

case class HumanReadableNumber(value: String)


val task1 = new Task[UnparsedNumber, ParsedPositiveNumber] {
def execute(configuration: UnparsedNumber): Option[ParsedPositiveNumber] = {
Try(configuration.value.toInt) match {
case Success(i) if i >= 0 => Some(ParsedPositiveNumber(i))
case Success(_) => None
case Failure(_) => None
}
}
}

val task2 = new Task[ParsedNumber, HumanReadableNumber] {
def execute(configuration: ParsedNumber): Option[HumanReadableNumber] = {
if(configuration.value < 1000 && configuration.value > -1000)
Some(HumanReadableNumber(s"The number is $configuration"))
else
None
}
}

val combined = task1.andThen(task2)

println(combined.execute(UnparsedNumber("12")))
println(combined.execute(UnparsedNumber("12x")))
println(combined.execute(UnparsedNumber("-12")))
println(combined.execute(UnparsedNumber("10000")))
println(combined.execute(UnparsedNumber("-10000")))

Try it out!


编辑:

关于您的评论,这种方法可能更符合您的要求:

case class Task[-C, +O](f: C => Option[O]) {

def execute(c: C): Option[O] = f.apply(c)
}

case class TaskChain[C, O <: C](tasks: List[Task[C, O]]) {

def run(initial: C): Option[O] = {

def runTasks(output: Option[C], tail: List[Task[C, O]]): Option[O] = {
output match {
case Some(o) => tail match {
case head :: Nil => head.execute(o)
case head :: tail => runTasks(head.execute(o), tail)
case Nil => ??? // This should never happen!
}
case None => None
}
}

runTasks(Some(initial), tasks)
}
}

// Example below:

val t1: Task[Int, Int] = Task(i => Some(i * 2))
val t2: Task[Int, Int] = Task(i => Some(i - 100))
val t3: Task[Int, Int] = Task(i => if(i > 0) Some(i) else None)


val chain: TaskChain[Int, Int] = TaskChain(List(t1, t2, t3))

println(chain.run(100))
println(chain.run(10))

Try it out!

引用:

您需要了解的是,如果您打包 Task s 在 List[Task]并将其用作 Task 的链s,输出必须至少是输入的一个子类型。 C <: TaskConfigurationO <: C导致:O <: C <: TaskConfiguration这也意味着 O <: TaskConfiguration .


如果您不理解其中的任何部分,我很乐意进一步解释。

希望对您有所帮助。

关于scala - 不同类型任务的功能组合 - Scala,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55124700/

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