Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
不同类型任务的功能组合-Scala_Scala_Function Composition - Fatal编程技术网

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

不同类型任务的功能组合-Scala,scala,function-composition,Scala,Function Composition,目前,我正在设计在Scala中构建通用管道(纯粹是为了学习)。为此,我从一个基本构造开始,Task接受一些TaskConfiguration(现在,我们可以假设这个TaskConfiguration是一个特定于任务功能的case类)。性状结构如下: trait Task[T <: TaskConfiguration] { type Out def taskConfiguration: T def execute(previousOutput: Option[Out]): Op

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

trait Task[T <: TaskConfiguration] {
  type Out

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

trait Task[T您可以使用与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")))

导入scala.util.{Try,Success,Failure}
类型TaskConfiguration=Any
特质任务[-C选项[O]){
def execute(c:c):选项[O]=f.apply(c)
}
案例类任务链[C,O尾部匹配{
案例头::Nil=>head.execute(o)
case head::tail=>runTasks(head.execute(o),tail)
case Nil=>???//这不应该发生!
}
案例无=>无
}
}
运行任务(一些(初始),任务)
}
}
//示例如下:
valt1:Task[Int,Int]=Task(i=>Some(i*2))
valt2:Task[Int,Int]=Task(i=>Some(i-100))
val t3:Task[Int,Int]=Task(i=>if(i>0)Some(i)else None)
val链:任务链[Int,Int]=任务链(列表(t1,t2,t3))
println(链运行(100))
println(链运行(10))

引述:


您需要了解的是,如果您将
任务
s打包到
列表[任务]
并将其用作
任务链
s,输出必须至少是输入的一个子类型。
C我建议看看能为您提供什么。按照这种方法,我将开始定义用于定义管道程序的ADT。类似于:

trait TaskE[Effect]
case class ReadTask[Input, SourceConfig](source: SourceConfig) extends TaskE[Input]
case class WriteTask[Output, SinkConfig](out: Output, sink: SinkConfig) extends TaskE[Unit]
然后应用免费monad(如上链接中所述)来定义管道流。类似于:

val pipeline: Task[Unit] = 
  for {
    input1 <- read(source1)
    input2 <- read(source2)
    _      <- write(input1 + input2, sink1)
  } yield ()

您可以拥有任意数量的“编译器”,但这并不意味着更改管道(“程序”)定义。

WDYM通过“编写要执行的方法调用”?@YuvalItzchakov这里我们处理的是列表[任务]并且需要对每个任务依次调用execute方法。这就像Task1的输出应该输入到Task2,依此类推。例如,如果管道类似于复制一个文件,那么相应的任务将是ReadTask,WriteTask。ReadTask将从文件中读取数据并将这些行提供给WriteTask,而后者又将写入另一个文件。No No No No modHFGen.dll如果您需要更多详细信息,请告诉我。感谢您的快速响应。看来,我的要求有点不同。“O”不是TaskConfiguration的子类型。它应该是类型成员(需要由Trait的子类重写),表示“execute”方法的输出。“execute”采用前面的方法“Task's execute method's output”作为输入。请参考我对Yuval问题的评论。如果出现错误,请纠正我。@Krishna听着,您需要了解的是,如果您将
任务
打包到
列表[任务]
并将其作为一个
任务链使用,输出必须至少是输入的一个子类型。
C@Krishna看一看这个例子:根据上面的评论更改了我的特征,效果很好。非常感谢。@Krishna很乐意帮助!@Santos free monads似乎是一个有趣的概念。但是,你的回答不是addressing the composition part.在给定的上下文中,我们将有一个需要组合的列表[Task],这与管道示例不同,在管道示例中,我事先知道存在多少任务及其执行顺序。
val pipeline: Task[Unit] = 
  for {
    input1 <- read(source1)
    input2 <- read(source2)
    _      <- write(input1 + input2, sink1)
  } yield ()
val myCompiler: Task ~> Id = ???
val tryCompiler: Task ~> Try = ???

pipeline.foldMap(myCompiler)  // Id[Unit]
pipeline.foldMap(tryCompiler) // Try[Unit]