Hello,
I am trying to make a small DSL that will allow me to compose different operations based on some set of external classes/objects. The domain is machine learning. So my initial attempt resulted in:
class AlgT[]
class ModelT[]
class DataT[]
class QueryT[]
class LabelT[]
class ResultT[]
class MetricT[_]
class Op[A, B]
object ML1 {
implicit object T1
implicit object T2
// (D->M) * ((Q,M) ->(R,M)) ~~> (D,Q) -> (R,M)
def bind[A, B, C, D](op1: Op[DataT[A], ModelT[B]],
op2: Op[(QueryT[C], ModelT[B]), (ResultT[D], ModelT[B])])(implicit d: T1.type)
: Op[(DataT[A], QueryT[C]), (ResultT[D], ModelT[B])] = ???
// ((D,Q) -> (R,M)) * ((L,R) -> E) ~~> (D,Q,L) -> E
def bind[A, B, C, D, E, F](op1: Op[(DataT[A], QueryT[B]), (ResultT[C], ModelT[D])],
op2: Op[(LabelT[E], ResultT[C]), MetricT[F]])(implicit d: T2.type)
: Op[(DataT[A], QueryT[B], LabelT[C]), MetricT[F]] = ???
}
Note that the implicits are their because of type erasure (bind is overloaded). So now I can do this:
val learn = new Op[DataT[Int], ModelT[Int]]
val predict = new Op[(QueryT[Int], ModelT[Int]), (ResultT[Boolean], ModelT[Int])]
val evaluate: Op[(LabelT[Boolean], ResultT[Boolean]), MetricT[Double]] = new Op[(LabelT[Boolean], ResultT[Boolean]), MetricT[Double]]
val learn_predict: Op[(DataT[Int], QueryT[Int]), (ResultT[Boolean], ModelT[Int])] = ML1.bind(learn, predict)
println(learn_predict)
val learn_predict_predict = ML1.bind(learn_predict, evaluate)
println(learn_predict_predict)
So far so good. But the syntax is awful and not DSL like. So I came up with the following classes:
implicit class ML1Z[A,B](op: Op[DataT[A], ModelT[B]]) {
def bindx[C, D](op2: Op[(QueryT[C], ModelT[B]), (ResultT[D], ModelT[B])])
: Op[(DataT[A], QueryT[C]), (ResultT[D], ModelT[B])] = ???
}
implicit class ML2Z[A,B,C,D](op: Op[(DataT[A], QueryT[B]), (ResultT[C], ModelT[D])]) {
def bindx[E, F](op2: Op[(LabelT[E], ResultT[C]), MetricT[F]])
: Op[(DataT[A], QueryT[B], LabelT[C]), MetricT[F]] = ???
}
Now I can do this:
import Base._
val l_p_1 = learn bindx predict bindx evaluate
println(l_p_1)
So my questions are:
- Is their any simpler way to this?
- Are their any potential problems with either of the “solutions” above?
TIA,
HF