Build generic reusable iteration module from higher order function

百般思念 提交于 2020-02-06 04:29:10

问题


How can I create a reusable module for iteration which allows me to:

  • choose whether it iterates in parallel
  • lets me specify a higher-order function of which tasks need to be performed

Here are some dummy functions. They for itself pose the second part of the question: Should I have an interface here that each of these functions at least implements the parameter inputDay:String? or is it better to have a generic function with a configuration class, where the configuration implements a minimal interface?

def doStuff(inputDay: String, inputConfigSomething: String): Unit = println(inputDay + inputConfigSomething)
def doOtherStuff(inputDay: String): Unit = println(inputDay)

Below an example of the iteration module first with a specific concrete iplementation of the task which is performed:

val days = Seq("20190101", "20190102", "20190103")
val something = "foo"

def iteration(d: Seq[String], parallel: Boolean = false) = {
  if (parallel) {
    d.par.foreach(dd => {
      println(dd)
    })
  } else {
    d.foreach(dd => {
      println(dd)
    })
  }
}

iteration(days)

Now, secondly, instead of concrete implementation a higher-order function should be passable to control what is computed. The code below unfortunately does not yet compile.

def iterationModule(d: Seq[String], functionToApply: Function, parallel: Boolean = false) = {
  if (parallel) {
    d.par.foreach(dd => {
      functionToApply(dd)
    })
  } else {
    d.foreach(dd => {
      functionToApply(dd)
    })
  }
}

iterationModule(days, doStuff)

Trying again with a more generic implementation. this seems to be too convoluted. There must be a simpler way. Also, it still fails to compile as I cannot dynamically instantiate C in the iteration module. Also, it is fairly annoying to type some of the Cs and Fs again and again.

trait MinimalIterationParameters {
  def inputDay: String
}

trait FunctionParameters

trait OperationService[C <: MinimalIterationParameters, F <: FunctionParameters] {
  def doOperation(config: C, functionParameter: F): Unit
}

case class Minimal(override val inputDay: String) extends MinimalIterationParameters

case class ExtendedThing(inputConfigSomething: String) extends FunctionParameters

object MyDummyOperationService extends OperationService[Minimal, ExtendedThing] {
  override def doOperation(config: Minimal, functionParameter: ExtendedThing): Unit = {
    println(config.inputDay + functionParameter.inputConfigSomething)
  }
}

def iterationModuleGeneric[C <: MinimalIterationParameters, F <: FunctionParameters](d: Seq[String], functionToApply: OperationService[C, F], f: F, parallel: Boolean = false) = {
  if (parallel) {
    d.par.foreach(dd => {
      functionToApply.doOperation(C(dd), f)
    })
  } else {
    d.foreach(dd => {
      functionToApply.doOperation(C(dd), f)
    })
  }
}

val c = Minimal
iterationModuleGeneric[Minimal, ExtendedThing](days, MyDummyOperationService, f = ExtendedThing("foo"))

edit

After seeing the first answer. Indeed, this is much simpler. So already a great step forward. However, I need to be able to pass the iterated item into the function as a parameter

    def iterationModule[A](d: Seq[A], functionToApply: A => Any, parallel: Boolean = false): Unit =
  if (parallel) {
    d.par.foreach(functionToApply)
  }
  else {
    d.foreach(functionToApply)
  }

    def doStuff(inputDay: String, inputConfigSomething: String): Unit = println(inputDay + inputConfigSomething)
    iterationModule[String](days, doStuff(d_each_reference, "foo"))

However:

iterationModule[String](days, doStuff(d_each_reference, "foo"))

will obviously not compile as d_each_reference is not defined there. How can I access the current iterated item and pass it to my function instead?

Also, trying to pass a flattened view of the iteration items and the configuration:

val configForIteration = days.map(d=> (d, something))
iterationModule[(String, String)](configForIteration, doStuff)

will not compile.


回答1:


Does this get a little closer to what you're after?

def iterationModule[A](d: Seq[A], functionToApply: A=>Any, parallel: Boolean = false) :Unit =
  if (parallel) d.par.foreach(functionToApply)
  else          d.foreach(functionToApply)

def doStuff(a:Char, b :String) :Unit = println(a+b)
iterationModule(List('X','Y','Z'), doStuff(_, "foo"))
//Xfoo
//Yfoo
//Zfoo


来源:https://stackoverflow.com/questions/59100295/build-generic-reusable-iteration-module-from-higher-order-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!