tod*_*d3a 4 monads scala stackless free-monad
以下代码改编自论文(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)))))))
Run Code Online (Sandbox Code Playgroud)
如何使用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))
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以使用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)
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以定义您的示例树:
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)
Run Code Online (Sandbox Code Playgroud)
让我们BinTree通过用包含其前任和后继的树替换每个叶子值来演示我们的同构和monad :
val newTree = to(
from(tree).flatMap(i => More[Pair, Int]((Done(i - 1), Done(i + 1))))
)
Run Code Online (Sandbox Code Playgroud)
重新格式化后,结果如下所示:
F((
F((
F((
F((L(0), L(2))),
F((L(1), L(3)))
)),
F((
F((L(2), L(4))),
F((L(3), L(5)))
)),
...
Run Code Online (Sandbox Code Playgroud)
等等,正如预期的那样.
对于你的第二个问题:如果你想为玫瑰树做同样的事情,你只需用列表(或流)替换它.你需要为列表提供一个functor实例,就像我们上面做的对,然后你有一个Done(x)代表叶子和More(xs)分支的树.
你的类型需要map为for-comprehension语法工作.幸运的是,您可以map根据以下内容编写flatMap和Done- 将以下内容添加到以下定义中Free:
def map[B](f: A => B): Free[S, B] = this.flatMap(f andThen Done.apply)
Run Code Online (Sandbox Code Playgroud)
现在以下内容与newTree上面完全相同:
val newTree = to(
for {
i <- from(tree)
m <- More[Pair, Int]((Done(i - 1), Done(i + 1)))
} yield m
)
Run Code Online (Sandbox Code Playgroud)
同样的事情将与Free[List, _]玫瑰树一起使用.
| 归档时间: |
|
| 查看次数: |
877 次 |
| 最近记录: |