gpt4 book ai didi

scala - Scala : Lists without "," 中的内部 DSL

转载 作者:行者123 更新时间:2023-12-04 16:31:46 24 4
gpt4 key购买 nike

我正在尝试在 Scala 中构建一个内部 DSL 来表示代数定义。让我们考虑这个简化的数据模型:

case class Var(name:String)
case class Eq(head:Var, body:Var*)
case class Definition(name:String, body:Eq*)

例如,一个简单的定义是:
val x = Var("x")
val y = Var("y")
val z = Var("z")
val eq1 = Eq(x, y, z)
val eq2 = Eq(y, x, z)
val defn = Definition("Dummy", eq1, eq2)

我想有一个内部 DSL 来表示这样一个形式的方程:
Dummy {
x = y z
y = x z
}

我能得到的最接近的是以下内容:
Definition("Dummy") := (
"x" -> ("y", "z")
"y" -> ("x", "z")
)

我遇到的第一个问题是我不能对 Definition 和 Var 进行两个隐式转换,因此 Definition("Dummy") .然而,主要问题是列表。我不想被任何东西包围,例如(),而且我也不希望它们的元素用逗号分隔。

使用 Scala 可以实现我想要的吗?如果是的话,谁能告诉我一个简单的方法来实现它?

最佳答案

虽然 Scalas 语法很强大,但它不够灵活,无法为符号创建任意定界符。因此,没有办法留下逗号并仅用空格替换它们。

尽管如此,还是可以使用宏并在编译时解析具有任意内容的字符串。这不是一个“简单”的解决方案,而是一个有效的解决方案:

object AlgDefDSL {

import language.experimental.macros

import scala.reflect.macros.Context

implicit class DefDSL(sc: StringContext) {
def dsl(): Definition = macro __dsl_impl
}

def __dsl_impl(c: Context)(): c.Expr[Definition] = {
import c.universe._

val defn = c.prefix.tree match {
case Apply(_, List(Apply(_, List(Literal(Constant(s: String)))))) =>

def toAST[A : TypeTag](xs: Tree*): Tree =
Apply(
Select(Ident(typeOf[A].typeSymbol.companionSymbol), newTermName("apply")),
xs.toList
)

def toVarAST(varObj: Var) =
toAST[Var](c.literal(varObj.name).tree)

def toEqAST(eqObj: Eq) =
toAST[Eq]((eqObj.head +: eqObj.body).map(toVarAST(_)): _*)

def toDefAST(defObj: Definition) =
toAST[Definition](c.literal(defObj.name).tree +: defObj.body.map(toEqAST(_)): _*)

parsers.parse(s) match {
case parsers.Success(defn, _) => toDefAST(defn)
case parsers.NoSuccess(msg, _) => c.abort(c.enclosingPosition, msg)
}
}
c.Expr(defn)
}

import scala.util.parsing.combinator.JavaTokenParsers

private object parsers extends JavaTokenParsers {

override val whiteSpace = "[ \t]*".r

lazy val newlines =
opt(rep("\n"))

lazy val varP =
"[a-z]+".r ^^ Var

lazy val eqP =
(varP <~ "=") ~ rep(varP) ^^ {
case lhs ~ rhs => Eq(lhs, rhs: _*)
}

lazy val defHead =
newlines ~> ("[a-zA-Z]+".r <~ "{") <~ newlines

lazy val defBody =
rep(eqP <~ rep("\n"))

lazy val defEnd =
"}" ~ newlines

lazy val defP =
defHead ~ defBody <~ defEnd ^^ {
case name ~ eqs => Definition(name, eqs: _*)
}

def parse(s: String) = parseAll(defP, s)
}

case class Var(name: String)
case class Eq(head: Var, body: Var*)
case class Definition(name: String, body: Eq*)
}

它可以与这样的东西一起使用:
scala> import AlgDefDSL._
import AlgDefDSL._

scala> dsl"""
| Dummy {
| x = y z
| y = x z
| }
| """
res12: AlgDefDSL.Definition = Definition(Dummy,WrappedArray(Eq(Var(x),WrappedArray(Var(y), Var(z))), Eq(Var(y),WrappedArray(Var(x), Var(z)))))

关于scala - Scala : Lists without "," 中的内部 DSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14536898/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com