从Scala中的一系列表达式构造List

Mic*_*ler 9 dsl scala

当我尝试在Scala中构建内部DSL时,遇到了一个常见问题,我无法制定解决方案.为了让事情看起来更像一种典型的语言,我希望语法看起来像这样:

model 'Foo {
  decl 'Real 'x;
  decl 'Real 'y;
}
Run Code Online (Sandbox Code Playgroud)

在实践中,有几个问题.第一个问题是在model这里获取一个对象以这种方式获取两个参数.如果有人有任何想法,请告诉我.但我所做的却是做一些更像这样的事情:

model('Foo) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

其中model现在是一个函数,然后使用一个apply方法返回一个对象,然后使用随后的lambda.我可以忍受.我也可以在lambda中遇到类似的问题,所以像内部decl 'Real 'x或类似的东西decl('Real,'x).但我想要做的是将所有这些表达式的结果放在波浪形的大括号中以作为列表"返回".换句话说,我想要写的是这样的东西:

model 'Foo {
  decl('Real,'x);
  decl('Real,'y);
}
Run Code Online (Sandbox Code Playgroud)

其中,decl(...)求值为某种类型Declaration,{...}然后求值为List[Declaration].我怀疑有一些方法可以使用implicits来做到这一点,但我一直无法找到它.简而言之,我想:

model 'Foo {
  decl('Real,'x);
  decl('Real,'y);
}
Run Code Online (Sandbox Code Playgroud)

...评估相当于......

model 'Foo {
  decl('Real,'x) ::
  decl('Real,'y) ::
  Nil
}
Run Code Online (Sandbox Code Playgroud)

意见或建议?

par*_*tic 4

作为第一个想法,您可以尝试变量参数列表,它允许您使用逗号而不是分号:

case class Declaration(name: String)

def decl( s: String ) = Declaration(s)

case class Model( sym: Symbol, decls: List[Declaration] )

def model( sym: Symbol)( decls: Declaration* ) =
  Model( sym, decls.toList )

val m = model( 'Foo )(
  decl( "bar" ), 
  decl( "baz" ) 
)
Run Code Online (Sandbox Code Playgroud)

或者,您可以扩展 atrait以去掉一些括号和逗号:

case class ModelBuilder( sym: Symbol ) {
  def using( decls: Declarations ) = Model( sym, decls.toList )
}

trait Declarations {

  protected var decls = List[Declaration]()

  protected def decl( s: String ) = 
decls ::= Declaration( s )

  def toList = decls
}

def model( sym: Symbol ) = ModelBuilder( sym )

model( 'Foo ) using new Declarations {
  decl( "bar" )
  decl( "baz" )
}
Run Code Online (Sandbox Code Playgroud)