Scala 游离单体与AST的关系
我指的是下面列出的Ken Scambler的源代码,另请参见Scala 游离单体与AST的关系,scala,monads,abstract-syntax-tree,Scala,Monads,Abstract Syntax Tree,我指的是下面列出的Ken Scambler的源代码,另请参见 包kenbot.free 进口scalaz_ 进口Scalaz_ 免进口_ 导入scala.collection.mutable //这个例子基于Runar Bjarnason的“死简单依赖注入”演讲中的一个例子。 // http://www.youtube.com/watch?v=ZasXwtTRkio // 0. 幻想API //def put(键:字符串,值:字符串):单位 //def get(键:字符串):字符串 //def
包kenbot.free
进口scalaz_
进口Scalaz_
免进口_
导入scala.collection.mutable
//这个例子基于Runar Bjarnason的“死简单依赖注入”演讲中的一个例子。
// http://www.youtube.com/watch?v=ZasXwtTRkio
// 0. 幻想API
//def put(键:字符串,值:字符串):单位
//def get(键:字符串):字符串
//def delete(键:字符串):单位
// 1. ADT
密封特征KVS[+下一步]
case类Put[Next](key:String,value:String,Next:Next)扩展KVS[Next]//Next)扩展KVS[Next]//Put(key,value,f(Next))
case Get(key,onResult)=>Get(key,onResult和then f)
案例删除(键,下一个)=>删除(键,f(下一个))
}
}
// 3. 提升功能
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):脚本[Unit]=liftF(delete(key,()))
// 4. 复合函数
def modify(key:String,f:String=>String):Free[KVS,Unit]=for{
v onResult(表(键))
大小写(键、值、下一个)=>表+=(键->值);下一个
案例删除(键,下一步)=>表-=键;下一步
}
}
如果一个脚本遵循这些,任何脚本(见源代码中的5)都会“转换”成类似于免费monad中的Suspend(Op(Suspend)(Op(…(Result(Op)))…)
不幸的是,5下面的脚本只是命令的线性序列
即使在网上搜索了几个小时,我也找不到任何例子,这些例子让我对以下问题有了更多的了解:
Suspend(Op(Suspend(Op(…(Result(Op))…)))
表示,因此是AST的一种表示形式?这一假设正确吗注意:请尽量坚持Scala/ScalaZ,因为Haskell(目前)不是我的专业领域。在ScalaZ中,
免费
单子作为两种情况(简化并忽略GoSub
优化):
让我们先看看免费的.liftF做了什么,例如
def get(key: String): Script[String] = liftF(Get(key, identity))
当执行get(“key”)
时,我们将获得
get("key")
// definition of get
liftF(Get("key",identity)
// definition of liftF
Suspend(Get("key",identity).map(Return)
// definition of map for Get above
Suspend(Get("key", identity andThen Return))
// identity andThen f == f
Suspend(Get("key", Return))
有了这些,让我们从你的问题开始:
Suspend
,要么是表示链末端的Return
作为一个具体示例,script
如下所示:
Suspend(Get("swiss-bank-account-id",
id => Suspend(Get(id,
v => Suspend(Put(id, v+1000000,
_ => Suspend(Put("bermuda-airport","getaway car",
_ => Suspend(Delete("tax-records",
_ => Return(())
))))))))))
val script2: Script[Unit] = for {
id <- get("swiss-bank-account-id")
_ <- cond(id == "123") {
Free.point[KVS,Unit](())
} {
for {
_ <- modify(id, ("LOTS OF " + _))
_ <- put("bermuda-airport", "getaway car")
_ <- delete("tax-records")
} yield ()
}
} yield ()
如您所见,我们基本上只是用计算的继续来“填充”函子的漏洞,以返回
结束。在示例DSL中,我们将始终有一个线性链,因为KVS
函子的每种情况都只有一个“漏洞”需要填充,因此没有分支
case class Cond[Next](cond: Boolean, ifTrue: Free[KVS,Next], ifFalse: Free[KVS,Next]) extends KVS[Next]
def cond[A](c: Boolean)(ifTrue: => Script[A])(ifFalse: => Script[A]): Script[A] =
liftF(Cond(c,ifTrue,ifFalse))
更改解释器案例后,可以如下使用:
Suspend(Get("swiss-bank-account-id",
id => Suspend(Get(id,
v => Suspend(Put(id, v+1000000,
_ => Suspend(Put("bermuda-airport","getaway car",
_ => Suspend(Delete("tax-records",
_ => Return(())
))))))))))
val script2: Script[Unit] = for {
id <- get("swiss-bank-account-id")
_ <- cond(id == "123") {
Free.point[KVS,Unit](())
} {
for {
_ <- modify(id, ("LOTS OF " + _))
_ <- put("bermuda-airport", "getaway car")
_ <- delete("tax-records")
} yield ()
}
} yield ()
val script3: Script[Unit] = for {
id <- get("swiss-bank-account-id")
_ <- if (id == "123") {
Free.point[KVS,Unit](())
} else {
for {
_ <- modify(id, ("LOTS OF " + _))
_ <- put("bermuda-airport", "getaway car")
_ <- delete("tax-records")
} yield ()
}
} yield ()
看看Monad.scala
和MonadSyntax.scala
,还有whileM
和iterateWhile
val script3: Script[Unit] = for {
id <- get("swiss-bank-account-id")
_ <- if (id == "123") {
Free.point[KVS,Unit](())
} else {
for {
_ <- modify(id, ("LOTS OF " + _))
_ <- put("bermuda-airport", "getaway car")
_ <- delete("tax-records")
} yield ()
}
} yield ()
val script4: Script[Unit] = modify("key",_+"!").untilM_ { get("key").map(_.length > 42) }
println(interpretPure(script4, Map("key" -> "")))
// Map(key -> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)