我有一些挫败感,试图找到在Scala中做某事的正确方法。我有一系列的操作,基本上是函数,编码为JSON列表。我想将这些列表元素解析到操作中,然后再执行操作以获得一些结果。
我将操作编码为案例类:
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/src/main/scala/leprechaun/leprechaun/leprechaun.scala#l13-l13-l68
和JSON分解为这些操作的列表:
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/src/main/scala/leprechaun/leprechaun/leprechaun.scala#l70-l96
很棒。现在恐怖了。我想一一执行这些操作,从一定值开始,然后依次应用每个操作。简单,听起来像是减少...
除非操作具有不同的签名。现在我被软管了。这是我唯一能想到的工作,它违反了我认为我应该使用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/src/main/scala/leprechaun/leprechaun/leprechaun.scala#l98-l98-l122
当然,这是错误的。我使用Any
类型的var
来保持正在操作的值,并匹配Operation
的类型并将其与输入一起施放,以实际调用操作。感觉不错,但我无法做任何其他工作。
我实际上使用下面的HLIST有希望的实现:
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/src/main/scala/leprechaun/leprechaun/leprechaun.scala#l124-l144
但是,我找不到将从JSON在运行时解析的Operations
列表转换为HLIST的方法...有没有办法做到这一点?
我参考作品的代码(您可以克隆并使用sbt test
:https://github.com/bmeg/leprechaun进行测试),但是必须有更好的方法。
任何洞察力都值得赞赏,谢谢您的帮助!
这无法解决您的主要问题,但是您可以替换
case VertexOperation(vertex) =>
anvil = operation.asInstanceOf[VertexOperation].blah
case op @ VertexOperation(_) =>
anvil = op.blah
消除一些.asInstanceOf