【问题标题】:Scala: How do I compose a list of operations into a free monad?Scala:如何将操作列表组合成一个免费的 monad?
【发布时间】:2016-11-30 21:44:56
【问题描述】:

我有一个免费的 monad 可以做我想做的事:

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(???) (??????)
}

将我的ListOperations 翻译成我可以通过我的解释器的免费monad 的正确方法是什么?

【问题讨论】:

  • 你不会在集合上映射Free.liftF,创建一个monads列表,然后使用monadic sequence函数来顺序组合monads吗?
  • @jon-hanson 这对我来说失败了,但我用sequenceU 替换了它,它成功了!显然这有一些 scala 问题:github.com/milessabin/si2712fix-plugin
  • 是的,sequenceUsequence 的 Unapply 变体,需要解决 SI-2712 - 更多信息 here

标签: scala free-monad


【解决方案1】:

在集合上映射Free.liftF,创建一个单子列表,然后使用单子sequence 函数(实际上是sequenceU,正如您所指出的那样)按顺序组合单子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 2020-03-26
    • 1970-01-01
    • 2010-09-06
    • 1970-01-01
    • 2018-07-08
    • 2022-08-18
    相关资源
    最近更新 更多