Hi,
I am experimenting with a very simple “piping” of functions. The idea is
to facilitate the combination of functions that take in a parameter P
,
an input I
and output some configuration related data A
and the processing
result O
. The input will most likely be a container of data (see end of example).
The idea is that I can sequence these operations and have the underlying
"system" automatically collect the A
s and pass the in/out to the next
function until processing has terminated.
The system is a function that is generated automatically (partial evaluation?).
This is done in partialEvalB
. The example below works ok, however it
seems a little complicated.
Can anyone suggest simplifications or ways to make it more manageable?
def func1a(p:String, v:Boolean): (String, Int) = (p, if (v) 1 else 0)
def func1b(p:Char, v:Int): (String, Double) = (p.toString, v.toDouble)
def func1c(p:String, v:Double) : (String, String) = (p, s"p($v)")
def func1d(p:Char, v:String) : (String, Double) = (p.toString, v.drop(2).dropRight(1).toDouble)
trait Monoid[T] {
def unit: T
def op(a:T, b:T) : T
}
object Monoids {
implicit object stringMonoid extends Monoid[String] {
def op(x: String, y: String): String = x.concat(y)
def unit: String = ""
}
implicit object intMonoid extends Monoid[Int] {
def op(x: Int, y: Int): Int = x + y
def unit: Int = 0
}
}
sealed trait OpB[A,P,I,IO,O]
case class LastOpBF[A,P,I,IO,O](p:P, f:(P,I) => (A,O)) extends OpB[A,P,I,IO,O]
case class OpBF[A,P1,I,O1,P2,O2](p:P1, f:(P1,I) => (A,O1), next: OpB[A,P2,O1,_,O2]) extends OpB[A,P1,I,O1,O2]
val exb0Op = LastOpBF('b', func1b)
val exb1Op = OpBF("func1a", func1a, exb0Op)
val exb2Op = OpBF("func1a", func1a, OpBF('b', func1b, OpBF("func1c", func1c, LastOpBF('d', func1d))))
def partialEvalB[A,P1,I,O1,P2,O2](o:OpB[A,P1,I,O1,O2])(implicit m: Monoid[A]): Iterable[(A,I)] => Iterable[(A, O2)] = o match {
case LastOpBF(p,f) => (is1:Iterable[(A,I)]) => {
val tmp: Iterable[(A, O2)] = is1.map{ i =>
val acc = i._1
val input = i._2
val (n_acc,output) = f(p,input)
(m.op(n_acc,acc), output)
}
tmp
}
case OpBF(p,f,next) =>
val f2: Iterable[(A,O1)] => Iterable[(A,O2)] = partialEvalB(next)(m)
(is1:Iterable[(A,I)]) => {
val tmp: Iterable[(A, O1)] = is1.map{ i =>
val acc = i._1
val input = i._2
val (n_acc,output) = f(p,input)
(m.op(n_acc,acc), output)
}
val tmp2: Iterable[(A, O2)] = f2(tmp)
tmp2
}
}
import Monoids._
val zero = List("","","","")
val exb1T: Iterable[(String, Int)] => Iterable[(String, Double)] = partialEvalB(exb0Op)
println(exb1T(zero.zip(List(1, 0, 0, 1))))
val exb2T: Iterable[(String, Boolean)] => Iterable[(String, Double)] = partialEvalB(exb1Op)
println(exb2T(zero.zip(List(true, false, false, true))))
val exb3T: Iterable[(String, Boolean)] => Iterable[(String, Double)] = partialEvalB(exb2Op)
println(exb3T(zero.zip(List(true, false, false, true))))