Stackless Scala和免费单子,完整示例

Stackless Scala和免费单子,完整示例,scala,monads,stackless,free-monad,Scala,Monads,Stackless,Free Monad,下面的代码改编自一篇论文(R.O.Bjarnason,Stackless Scala和免费单子) 本文的标题指出了所提出的数据结构的一般用途,即在常量堆栈空间中提供递归处理,并让用户以清晰的方式表示递归 具体地说,我的目标是拥有一元结构,在升序时基于恒定堆栈空间中的简单模式匹配,提供对不可变的成对树(二叉树)或列表树(n元树)的结构重写 sealed trait Free[S[+_], +A]{ private case class FlatMap[S[+_], A, +B]( a:

下面的代码改编自一篇论文(R.O.Bjarnason,Stackless Scala和免费单子)

本文的标题指出了所提出的数据结构的一般用途,即在常量堆栈空间中提供递归处理,并让用户以清晰的方式表示递归

具体地说,我的目标是拥有一元结构,在升序时基于恒定堆栈空间中的简单模式匹配,提供对不可变的成对树(二叉树)或列表树(n元树)的结构重写

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块内完成吗


[问题已编辑。]

更新:下面的答案解决了问题,但大部分仍然相关


首先,您的代码将无法正常工作。您可以使所有内容保持不变,也可以使用原始纸张中的方差注释。为了简单起见,我将采用不变路径(参见完整示例),但我刚刚确认本文中的版本将在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
的单子:

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)))
    )),
    ...
如期而至

对于你的第二个问题:如果你想对一棵玫瑰树做同样的事情,你只需要用一个列表(或一个流)替换这对。您将需要为列表提供一个函子实例,就像我们在上面为pairs所做的那样,然后您将得到一个树,其中
Done(x)
表示叶,而
More(xs)
表示分支


您的类型需要
映射
,才能使用
理解语法。幸运的是,您可以根据
flatMap
Done
编写
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
)
val newTree=to(
为了{

树操作是如何实现的…tree.flatMap(i=>More[List,Int](List(Done(i-1),Done(i+1)))然后在for block?函数中实现(tree:BinTree[Int]):T不是递归的,也不是蹦床,这是Free作为广义蹦床的目的。@tod3a:Right的
to
from
方法只是为了显示这两种树类型具有相同的形状。
T
没有蹦床的事实是重点。目的是要有一个一元结构,使rds(无限制)基于恒定堆栈空间中的简单模式匹配重写不可变树。使用Free而不是T将排除以升序方式(不可变)遍历时在结构上重写树的可能性(而不仅仅是附加叶子)。我无法在Free中发现钩子,以便在整个树上进行模式匹配并向上重写树。在for块中,只有叶子是可访问的;函子用于向下,省略了顶部分叉。最后,我发现,我做出了错误的选择。Free是用于此目的的错误单子。它有助于枚举树的叶子,但没有以一种有助于自下而上重建(不可变)树的方式枚举子树。因此,@tailrec final def rec(tree:RoseTree[Int]):RoseTree[Int]=tree.resume match{case Left(l)=>More[List,Int](有效映射[RoseTree[Int],RoseTree[Int]](rec,l))case Right(i)=>Done[List,Int](i)}将导致错误,如果不引入其他构造,则没有任何帮助。