问题
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