I am having some frustrations trying to find the right way to do something in Scala. I have a series of operations, basically functions, encoded as a json list. I want to parse these list elements into operations and perform the operations one after the other to get some result.

I have the operations encoded as case classes:

sealed trait Operation case class VertexOperation(vertex: String) extends Operation { def operate(input: ScalaGraph): GremlinScala[Vertex, HNil] = { input.V.hasLabel(vertex) } } case class InOperation(in: String) extends Operation { def operate[Labels <: HList](input: GremlinScala[Vertex, Labels]): GremlinScala[Vertex, Labels] = { input.in(in) } } ..............

https://github.com/bmeg/leprechaun/blob/master/src/main/scala/leprechaun/Leprechaun.scala#L13-L68

and the json parsed into a list of these operations:

object Query { class OperationSerializer extends CustomSerializer[Operation](format => ({ case JObject(List(JField("vertex", JString(vertex)))) => VertexOperation(vertex) case JObject(List(JField("in", JString(in)))) => InOperation(in) case JObject(List(JField("out", JString(out)))) => case JObject(List(JField("outVertex", JString(outVertex)))) => OutVertexOperation(outVertex) ........... }, { case VertexOperation(vertex) => JObject(JField("vertex", JString(vertex))) case InOperation(in) => JObject(JField("in", JString(in))) .......... })) implicit val formats = Serialization.formats(NoTypeHints) + new OperationSerializer() def fromJson(json: JValue): Query = { json.extract[Query] } def fromString(raw: String): Query = { val json = parse(raw) fromJson(json) } }

https://github.com/bmeg/leprechaun/blob/master/src/main/scala/leprechaun/Leprechaun.scala#L70-L96

Awesome. Now comes the horror. I want to perform these operations one by one, starting with some value, and applying each operation in turn upon the result of the last. Easy, sounds like a reduction...

Except the operations have different signatures. Now I am hosed. This is the only thing I could come up with that works, that violates everything about how I think I am supposed to use Scala:

case class Query(query: List[Operation]) { // def operate[R, In <: HList, G](graph: ScalaGraph) (implicit p: Prepend[In, ::[G, HNil]]): R = { def operate[R](graph: ScalaGraph): R = { var anvil: Any = graph def op[M](operation: Operation) { operation match { case VertexOperation(vertex) => anvil = operation.asInstanceOf[VertexOperation].operate(anvil.asInstanceOf[ScalaGraph]) case InOperation(in) => anvil = operation.asInstanceOf[InOperation].operate(anvil.asInstanceOf[GremlinScala[Vertex, HList]]) case OutVertexOperation(outVertex) => anvil = operation.asInstanceOf[OutVertexOperation].operate(anvil.asInstanceOf[GremlinScala[Edge, HList]]) ............. } } query.foreach(x => op(x)) anvil.asInstanceOf[R] } }

https://github.com/bmeg/leprechaun/blob/master/src/main/scala/leprechaun/Leprechaun.scala#L98-L122

Surely, this is wrong. I am using a var of type Any to hold the value being operated on, and match the type of the Operation and cast it, along with the input, to actually call the operation. It feels wrong, but I can't get anything else to work.

I actually have a hopeful implementation using an HList below that:

trait ApplyOperationDefault extends Poly2 { implicit def default[T, L <: HList] = at[T, L] ((_, acc) => acc) } object ApplyOperation extends ApplyOperationDefault { implicit def vertex[T, L <: HList, S <: HList] = at[VertexOperation, ScalaGraph] ((t, acc) => t.operate(acc)) implicit def has[M, T, L <: HList, S <: HList] = at[HasOperation[M], GremlinScala[Vertex, S]] ((t, acc) => t.operate(acc)) implicit def as[A, T, L <: HList, In <: HList](implicit p: Prepend[In, ::[A, HNil]]) = at[AsOperation, GremlinScala[A, In]] ((t, acc) => t.operate(acc)) implicit def in[T, L <: HList, S <: HList] = at[InOperation, GremlinScala[Vertex, S]] ((t, acc) => t.operate(acc)) implicit def out[T, L <: HList, S <: HList] = at[OutOperation, GremlinScala[Vertex, S]] ((t, acc) => t.operate(acc)) ............. } object Operation { def process[Input, Output, A <: HList](operations: A, input: Input) (implicit folder: RightFolder.Aux[A, Input, ApplyOperation.type, Output]): Output = { operations.foldRight(input) (ApplyOperation) } }

https://github.com/bmeg/leprechaun/blob/master/src/main/scala/leprechaun/Leprechaun.scala#L124-L144

But, I can't find a way to translate the list of Operations parsed from Json at runtime into an HList... is there a way to do that?

The code I am referencing works (you can clone and test it with sbt test : https://github.com/bmeg/leprechaun ) but there has to be a better way.

Any insight appreciated, thank you for your help!