繁体   English   中英

Stackless Scala With Free Monads,完整的例子

[英]Stackless Scala With Free Monads, complete example

以下代码改编自论文(RO Bjarnason,Stackless Scala With Free Monads)。

本文的标题总体上指出了所提出的数据结构的目的 - 即在常量堆栈空间中提供递归处理,并让用户以清晰的方式表达递归。

具体来说,我的目标是建立一个monadic结构,在升序时基于恒定堆栈空间中的简单模式匹配,提供不可变树对(二叉树)或列表(n-ary-tree)的结构重写。

sealed trait Free[S[+_], +A]{
  private case class FlatMap[S[+_], A, +B](
    a: Free[S, A],
    f: A => Free[S, B]
  ) extends Free[S, B]

  def map[B](f: A => B): Free[S, B] = this.flatMap((a:A) => Done[S, B](f(a))) 

  def flatMap[B](f: A => Free[S, B]): Free[S, B] = this match { 
    case FlatMap(a, g) => FlatMap(a, (x: Any) => g(x).flatMap(f))
    case x => FlatMap(x, f)
  } 

  @tailrec
  final def resume(implicit S: Functor[S]): Either[S[Free[S, A]], A] = {
    this match {
      case Done(a) => Right(a)
      case More(k) => Left(k)
      case FlatMap(a, f) => a match {
        case Done(a) => f(a).resume
        case More(k) => Left(S.map(k)((x)=>x.flatMap(f)))
        case FlatMap(b, g) => b.flatMap((x: Any) => g(x).flatMap(f)).resume
      }
    }
  }
}

case class Done[S[+_], +A](a: A) extends Free[S, A]

case class More[S[+_], +A](k: S[Free[S, A]]) extends Free[S,A]

trait Functor[F[+_]] {
  def map[A, B](m: F[A])(f: A => B): F[B]
}

type RoseTree[+A] = Free[List, A] 

implicit object listFunctor extends Functor[List] {
  def map[A, B](a: List[A])(f: A => B) = a.map(f)
}
var tree :  Free[List, Int]=  More(List(More(List(More(List(Done(1), Done(2))), More(List(Done(3), Done(4))))), More(List(More(List(Done(5), Done(6))), More(List(Done(7), Done(8)))))))

如何使用Free实现重写?

模式匹配器的钩子在哪里? - 上升时,模式匹配器必须暴露给每个完整的子树!

这可以在for block中完成吗?

[问题已被编辑。]

更新:下面的答案解决问题的早期版本 ,但大多数仍然相关。


首先,您的代码不会按原样运行。 您可以使所有内容保持不变,也可以使用原始论文中的方差注释。 为了简单起见,我将采用不变的路线(请参见此处获得完整的示例),但我也刚刚确认本文中的版本适用于2.10.2。

首先回答你的第一个问题:你的二叉树类型与BinTree[Int]是同构的。 不过,在我们展示这个之前,我们需要一个类型的仿函数:

implicit object pairFunctor extends Functor[Pair] {
  def map[A, B](a: Pair[A])(f: A => B) = (f(a._1), f(a._2))
}

现在我们可以使用resume ,我们需要从BinTree转换回T

def from(tree: T): BinTree[Int] = tree match {
  case L(i) => Done(i)
  case F((l, r)) => More[Pair, Int]((from(l), from(r)))
}

def to(tree: BinTree[Int]): T = tree.resume match {
  case Left((l, r)) => F((to(l), to(r)))
  case Right(i) => L(i)
}

现在我们可以定义您的示例树:

var z = 0
def f(i: Int): T = if (i > 0) F((f(i - 1), f(i - 1))) else { z = z + 1; L(z) }
val tree = f(3)

让我们通过用包含其前任和后继的树替换每个叶子值来演示我们的同构和BinTree的monad:

val newTree = to(
  from(tree).flatMap(i => More[Pair, Int]((Done(i - 1), Done(i + 1))))
)

重新格式化后,结果如下所示:

F((
  F((
    F((
      F((L(0), L(2))),
      F((L(1), L(3)))
    )),
    F((
      F((L(2), L(4))),
      F((L(3), L(5)))
    )),
    ...

等等,正如预期的那样。

对于你的第二个问题:如果你想为玫瑰树做同样的事情,你只需用列表(或流)替换它。 你需要为列表提供一个functor实例,正如我们上面对的那些,然后你有一个树,其中Done(x)代表叶子,而More(xs)代表分支。


您的类型需要map才能使for comprehension语法起作用。 幸运的是,您可以根据flatMapDone编写map只需将以下内容添加到Free的定义中:

def map[B](f: A => B): Free[S, B] = this.flatMap(f andThen Done.apply)

现在,以下内容与上面的newTree完全相同:

val newTree = to(
  for {
    i <- from(tree)
    m <- More[Pair, Int]((Done(i - 1), Done(i + 1)))
  } yield m
)

同样的事情将与Free[List, _]玫瑰树一起使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM