Scala、gremlin-scala、HLists、Poly2、RightFold 和缺失的隐式 Prepend
Scala, gremlin-scala, HLists, Poly2, RightFold and a missing implicit Prepend
所以,我试图将 gremlin-scala
中的一系列操作封装到 HList
中,这样我就可以对它们执行 RightFold
(这将允许我构建一个 gremlin作为数据查询:特别是 Operations
的 HList
)。
这就是我的意思:通常你可以这样调用 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))
一切都很好,但我希望能够将查询构造为数据。我将其建模为 Operations
的 HList
,如下所示:
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的使用。编译器会自动为你生成它,你永远不需要手动创建它。
如中所述,Prepend
用于保留标记步骤的类型。 gremlin-scala readme.md 更深入。
编译器实际上告诉你它需要什么:
could not find implicit value for parameter p: shapeless.ops.hlist.Prepend[In,shapeless.::[A,shapeless.HNil]]
这就是我所做的:向作用域添加隐式前置 :)
我刚给你发了一个 PR,现在可以正常编译了。
PS:您可能想要更新您的 gremlin-scala 版本。
所以,我试图将 gremlin-scala
中的一系列操作封装到 HList
中,这样我就可以对它们执行 RightFold
(这将允许我构建一个 gremlin作为数据查询:特别是 Operations
的 HList
)。
这就是我的意思:通常你可以这样调用 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))
一切都很好,但我希望能够将查询构造为数据。我将其建模为 Operations
的 HList
,如下所示:
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的使用。编译器会自动为你生成它,你永远不需要手动创建它。
如Prepend
用于保留标记步骤的类型。 gremlin-scala readme.md 更深入。
编译器实际上告诉你它需要什么:
could not find implicit value for parameter p: shapeless.ops.hlist.Prepend[In,shapeless.::[A,shapeless.HNil]]
这就是我所做的:向作用域添加隐式前置 :) 我刚给你发了一个 PR,现在可以正常编译了。
PS:您可能想要更新您的 gremlin-scala 版本。