Scala的方法是什么?案例类别序列化为JSON代表一系列操作



我有一些挫败感,试图找到在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

最新更新