Scala、gremlin-scala、HLists、Poly2、RightFold 和缺失的隐式 Prepend

标签 scala types gremlin shapeless hlist

因此,我尝试将 gremlin-scala 中的一系列操作封装到 HList 中,以便我可以对它们执行 RightFold (这将允许我将 gremlin 查询构造为数据:特别是 OperationsHList)。

这就是我的意思:通常你可以像这样调用gremlin-scala:

import gremlin.scala._
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory

def graph = TinkerFactory.createModern.asScala
graph.V.hasLabel("person").out("created").as("creations").toList.map(_.valueMap)

---> List[Map[String,Any]] = List(Map(name -> lop, lang -> java), Map(name -> ripple, lang -> java), Map(name -> lop, lang -> java), Map(name -> lop, lang -> java))

这一切都很好,但我希望能够将查询构造为数据。我将其建模为 OperationsHList,如下所示:

sealed trait Operation

case class VertexOperation[Labels <: HList](vertex: String) extends Operation {
  def operate(graph: Graph): GremlinScala[Vertex, Labels] = {
    graph.V.hasLabel(vertex).asInstanceOf[GremlinScala[Vertex, Labels]]
  }
}

case class OutOperation[Labels <: HList](out: String) extends Operation {
  def operate(vertex: GremlinScala[Vertex, Labels]): GremlinScala[Vertex, Labels] = {
    vertex.out(out)
  }
}

然后我就可以通过将它们放入 HList 中来创建查询,如下所示:

import shapeless._

val query = OutOperation("created") :: VertexOperation("person") :: HNil

现在我已将这些放入 HList 中,我可以执行 RightFold 将它们一一应用到图表中:

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[S], Graph] ((t, acc) => t.operate(acc))
  implicit def out[T, L <: HList, S <: HList] = at[OutOperation[S], 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)
  }
}

并这样调用它:

val result = Operation.process(query, graph).toList

这一切都有效!并显示出巨大的前景。

这里是我遇到问题的地方:当我尝试使用 as 操作执行此操作时,我可以编译 Operation:

case class AsOperation[A, In <: HList](step: String) extends Operation {
  def operate(g: GremlinScala[A, In]) (implicit p: Prepend[In, ::[A, HNil]]): GremlinScala[A, p.Out] = {
    g.as(step)
  }
}

(我在那里添加了 (implicit p: Prepend[In,::[A, HNil]]) 因为编译器否则会提示)...但是当我尝试创建对于这种情况以及其他情况的隐式处理程序,它失败了:

implicit def as[T, L <: HList, A, In <: HList] = at[AsOperation[A, In], GremlinScala[A, In]] ((t, acc) => t.operate(acc))

---> could not find implicit value for parameter p: shapeless.ops.hlist.Prepend[In,shapeless.::[A,shapeless.HNil]]

所以,这里有几个问题:

  • 这个隐式 Prepend 是什么意思,为什么我需要它?
  • 为什么正常调用as时可以找到隐式的Prepend,但尝试RightFold时却找不到?
  • 如何创建 Prepend 的隐式实例?
  • 创建后,如何将其传递给 operate 的调用?
  • 正确的做法是什么?

我可能还有更多问题,但这些是主要问题。我一直在阅读类型级编程和一般的无形编程,我真的很喜欢它,但这种东西令人发狂。我知道我在这里缺少一些微妙的东西,但很难知道从哪里开始破译缺少的东西。

感谢您的帮助!我真的很想热爱scala和Shapeless,希望尽快克服这个障碍。

编辑:我在这里制作了一个最小的存储库来重现问题:https://github.com/bmeg/leprechaun

希望有帮助!

最佳答案

你的误解是Prepend的使用。编译器会自动为您生成它,您无需手动创建它。

Shapeless and gremlin scala: How do I return the result of a call to `as`? 中所述Prepend 用于保留标记步骤的类型。 gremlin-scala readme.md 更深入。

编译器实际上会准确地告诉您它需要什么: 无法找到参数 p 的隐式值:shapeless.ops.hlist.Prepend[In,shapeless.::[A,shapeless.HNil]]

这就是我所做的:向范围添加隐式 Prepend :) 我刚刚给你发了一条PR ,现在编译得很好。

PS:您可能想要更新 gremlin-scala 版本。

关于Scala、gremlin-scala、HLists、Poly2、RightFold 和缺失的隐式 Prepend,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40754229/

相关文章:

docker - Cayley Docker没有写数据

scala - 为什么 Scala + Intellij + ScalaTest + Scalactic 出现 "could not find implicit"错误,但不是来自 sbt

Scala-zip 与 future

java - Java 中的同步构造是否在内部(以某种方式)使用硬件原语 CAS 操作?

python - 在python中将类似字符串的对象转换为字符串

Python - 定义对象返回值

docker - 没有此类属性:类:Script4的ToInputStream

scala 将字符串转换为泛型类型

module - 在 Ocaml map 库中输入 +'a t?

graph - 我可以使用 CosmosDB(图形 API)中的触发器根据文档负载自动创建边缘吗?