У меня есть свободная монады работа, которая делает то, что я хочу:Scala: Как составить список операций в бесплатную монаду?
type FreeOperation[F] = Free[Operation, F]
sealed trait Operation[O]
case object IdentityOperation extends Operation[GraphTraversal[_, _]]
case class LabelOperation(label: String) extends Operation[GraphTraversal[_, Vertex]]
case class HasOperation(has: String, within: List[_]) extends Operation[GraphTraversal[_, Vertex]]
case class InOperation(in: String) extends Operation[GraphTraversal[_, Vertex]]
case class OutOperation(out: String) extends Operation[GraphTraversal[_, Vertex]]
case class InEdgeOperation(inEdge: String) extends Operation[GraphTraversal[_, Edge]]
case class OutEdgeOperation(outEdge: String) extends Operation[GraphTraversal[_, Edge]]
case class InVertexOperation(inVertex: String) extends Operation[GraphTraversal[_, Vertex]]
case class OutVertexOperation(outVertex: String) extends Operation[GraphTraversal[_, Vertex]]
case class AsOperation(as: String) extends Operation[GraphTraversal[_, _]]
case class SelectOperation(select: List[String]) extends Operation[GraphTraversal[_, _]]
object Operation {
def identity: FreeOperation[GraphTraversal[_, _]] = Free.liftF(IdentityOperation)
def label(v: String): FreeOperation[GraphTraversal[_, Vertex]] = Free.liftF(LabelOperation(v))
def has(h: String, w: List[_]): FreeOperation[GraphTraversal[_, Vertex]] = Free.liftF(HasOperation(h, w))
def in(i: String): FreeOperation[GraphTraversal[_, Vertex]] = Free.liftF(InOperation(i))
def out(o: String): FreeOperation[GraphTraversal[_, Vertex]] = Free.liftF(OutOperation(o))
def inEdge(ie: String): FreeOperation[GraphTraversal[_, Edge]] = Free.liftF(InEdgeOperation(ie))
def outEdge(oe: String): FreeOperation[GraphTraversal[_, Edge]] = Free.liftF(OutEdgeOperation(oe))
def inVertex(iv: String): FreeOperation[GraphTraversal[_, Vertex]] = Free.liftF(InVertexOperation(iv))
def outVertex(ov: String): FreeOperation[GraphTraversal[_, Vertex]] = Free.liftF(OutVertexOperation(ov))
def as(a: String): FreeOperation[GraphTraversal[_, _]] = Free.liftF(AsOperation(a))
def select(s: List[String]): FreeOperation[GraphTraversal[_, _]] = Free.liftF(SelectOperation(s))
}
def operationInterpreter(traversal: GraphTraversal[_, _]): (Operation ~> Id) =
new (Operation ~> Id) {
def apply[A](input: Operation[A]): Id[A] =
input match {
case IdentityOperation => traversal.asInstanceOf[A]
case LabelOperation(label) => traversal.hasLabel(label).asInstanceOf[A]
case HasOperation(has, within) => traversal.has(has, P.within(within: _*)).asInstanceOf[A]
case InOperation(in) => traversal.in(in).asInstanceOf[A]
case OutOperation(out) => traversal.out(out).asInstanceOf[A]
case InEdgeOperation(inEdge) => traversal.inE(inEdge).asInstanceOf[A]
case OutEdgeOperation(outEdge) => traversal.outE(outEdge).asInstanceOf[A]
case InVertexOperation(inVertex) => traversal.inV().asInstanceOf[A]
case OutVertexOperation(outVertex) => traversal.outV().asInstanceOf[A]
case AsOperation(as) => traversal.as(as).asInstanceOf[A]
case SelectOperation(select) => {
if (select.isEmpty) {
traversal
} else if (select.size == 1) {
traversal.select[Any](select.head).asInstanceOf[A]
} else {
traversal.select[Any](select.head, select.tail.head, select.tail.tail: _*)
}
}
}
}
Я могу назвать это как так, чтобы создать программу:
def selectQuery: Free[Operation, GraphTraversal[_, _]] =
for {
_ <- label("person")
_ <- as("people")
_ <- outEdge("created")
_ <- has("weight", List(1.0))
_ <- inVertex("software")
_ <- as("software")
x <- select(List("people", "software"))
} yield x
val traversal = graph.traversal.V()
val result = selectQuery.foldMap(operationInterpreter(traversal))
Круто! Но вот в чем проблема:
У меня есть List[Operation]
, что я хотел бы перевести на эту монадическую структуру ... как это сделать?
def composeQuery(query: List[Operation[_]]): FreeOperation[GraphTraversal[_, _]] = {
query.foldLeft(???) (??????)
}
Что такое правильный способ перевести мой List
из Operations
в свободную монаду, что я могу передать мой переводчик?
Не могли бы вы отобразить 'Free.liftF' над коллекцией, создать список монадов, а затем использовать монадическую функцию' sequence', чтобы последовательно составлять монады? –
@ jon-hanson Это было неудачно для меня, но я заменил его 'sequenceU', и он сработал! По-видимому, для этого существует проблема scala: https://github.com/milessabin/si2712fix-plugin – prismofeverything
Да, 'sequenceU' - это вариант Unapply' sequence', необходимый для работы [SI-2712] (https://issues.scala-lang.org/browse/SI-2712) - больше информации [здесь] (http://eed3si9n.com/herding-cats/Unapply.html). –