我指的是下面列出的Ken Scambler的源代码,也请参阅GitHub source。免费单子和AST的关系
package kenbot.free
import scalaz._
import Scalaz._
import Free._
import scala.collection.mutable
// This example is based off the one in Runar Bjarnason's "Dead Simple Dependency Injection" talk.
// http://www.youtube.com/watch?v=ZasXwtTRkio
// 0. Fantasy API
// def put(key: String, value: String): Unit
// def get(key: String): String
// def delete(key: String): Unit
// 1. ADT
sealed trait KVS[+Next]
case class Put[Next](key: String, value: String, next: Next) extends KVS[Next] // <---- def put(key: String, value: String): Unit
case class Get[Next](key: String, onResult: String => Next) extends KVS[Next] // <---- def get(key: String): String
case class Delete[Next](key: String, next: Next) extends KVS[Next] // <---- def delete(key: String): Unit
object KVS {
type Script[A] = Free[KVS, A]
// 2. Functor definition
implicit val functor: Functor[KVS] = new Functor[KVS] {
def map[A,B](kvs: KVS[A])(f: A => B): KVS[B] = kvs match {
case Put(key, value, next) => Put(key, value, f(next))
case Get(key, onResult) => Get(key, onResult andThen f)
case Delete(key, next) => Delete(key, f(next))
}
}
// 3. Lifting functions
def put(key: String, value: String): Script[Unit] = liftF(Put(key, value,()))
def get(key: String): Script[String] = liftF(Get(key, identity))
def delete(key: String): Script[Unit] = liftF(Delete(key,()))
// 4. Composite functions
def modify(key: String, f: String => String): Free[KVS, Unit] = for {
v <- get(key)
_ <- put(key, f(v))
} yield()
// 5. Write scripts
val script: Free[KVS, Unit] = for {
id <- get("swiss-bank-account-id")
_ <- modify(id, (_ + 1000000))
_ <- put("bermuda-airport", "getaway car")
_ <- delete("tax-records")
} yield()
// 6. Interpreters
// Building an immutable structure
def interpretPure(kvs: Script[Unit], table: Map[String, String] = Map.empty): Map[String, String] = kvs.resume.fold({
case Get(key, onResult) => interpretPure(onResult(table(key)), table)
case Put(key, value, next) => interpretPure(next, table + (key -> value))
case Delete(key, next) => interpretPure(next, table - key)
}, _ => table)
// Directly running effects
def interpretImpure(kvs: Script[Unit], table: mutable.Map[String, String]): Unit = kvs.go {
case Get(key, onResult) => onResult(table(key))
case Put(key, value, next) => table += (key -> value); next
case Delete(key, next) => table -= key; next
}
}
如果按照下列slides,任何脚本(见源代码5)被“转化”成免费的单子中类似Suspend(Op(Suspend(Op(......(Result(Op))..))
。
不幸的是,5下的脚本只是一个线性的命令序列。
即使搜索了几个小时的网在,我无法找到任何的例子,给了以下的问题更深入的了解:
- 线性操作的顺序(这也是树当然)由
Suspend(Op(Suspend(Op(......(Result(Op))..))
表示,并且因此是AST的表示。这个假设是正确的吗? - AST如何表示真实表示免费单子内的AST?我认为,发生这种情况时,包括控制结构? (例如根据条件左右树枝)。有人可以举例说明一个真正的AST起作用的例子吗?也许,举例说明如何在给定的例子中实现“if”。 (?在源代码下5给出)
- 什么是一般的方法,包括控制结构成脚本
PS:请尝试坚持斯卡拉/ ScalaZ,因为Haskell是(还)没有我的领域的专业知识。