加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Stackless Scala With Free Monads,完整的例子

发布时间:2020-12-16 18:04:21 所属栏目:安全 来源:网络整理
导读:以下代码改编自论文(R.O.Bjarnason,Stackless Scala With Free Monads). 本文的标题总体上指出了所提出的数据结构的目的 – 即在常量堆栈空间中提供递归处理,并让用户以清晰的方式表达递归. 具体来说,我的目标是建立一个monadic结构,在升序时基于恒定堆栈空
以下代码改编自论文(R.O.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中完成吗?

[问题已被编辑.]

解决方法

更新:下面的答案解决了问题的 an earlier version,但大多数仍然相关.

首先,您的代码不会按原样运行.您可以使所有内容保持不变,也可以使用原始论文中的方差注释.为了简单起见,我将采用不变的路线(参见here的完整示例),但我也刚刚确认论文中的版本适用于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)代表叶子,而更多(xs)代表分支.

您的类型需要映射才能使用for-comprehension语法.幸运的是,您可以根据flatMap和Done编写地图 – 只需将以下内容添加到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,Done(i + 1)))
  } yield m
)

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读