Scala 游离单体与AST的关系

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

我指的是下面列出的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 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的一种表示形式?这一假设正确吗
  • 在自由单子中,真实的AST是如何表示的?我假设,当包含控制结构时会发生这种情况(例如,根据条件,左树分支和右树分支)。有人能举例说明真实的AST是如何发挥作用的吗?也许,在给定的例子中可以举例说明如何实现“如果”
  • 将控制结构包含到脚本中的一般方法是什么(如源代码第5节所述?)

  • 注意:请尽量坚持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(Op(Suspend(Op(…(Result(Op))表示)表示,因此是AST的表示形式?这一假设正确吗
  • 本质上是的,在DSL中使用由函子产生的自由单子编写的程序表示一个“步骤链”,其中每个步骤要么是包含一个函子案例的
    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
    函子的每种情况都只有一个“漏洞”需要填充,因此没有分支

  • 在自由单子中,真实的AST是如何表示的?我假设,当包含控制结构时会发生这种情况(例如,根据条件,左树分支和右树分支)。有人能举例说明真实的AST是如何发挥作用的吗?也许,在给定的例子中可以举例说明如何实现“如果”
  • 让我们用分支构造扩展DSL:

    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 ()
    
  • 将控制结构包含到脚本中的一般方法是什么(如源代码第5节所述?)
  • 首先,请记住,例如,您可以使用标准if inside进行理解:

    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 -> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)