Construct a List from a series of expressions in Scala

dsl, scala

Solution

As a first idea, you could try variable arguments lists, which allows you to use commas instead of semi-colons:

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

Alternatively, you could extend a `trait` to get rid of some parentheses and of the commas:

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" )
}

Problem

When I try to build internal DSLs in Scala, I run into a common problem and I haven't been able to craft a solution. To make things look a bit more like a typical language, I'd like the syntax to look something like this: ``` model 'Foo { decl 'Real 'x; decl 'Real 'y; } ``` In practice, there are several issues. The first issue is getting a `model` object here to take two arguments in this way. If anybody has any ideas, let me know. But what I've done instead is to do something a bit more like this: ``` model('Foo) { ... } ``` Where model is now a function which then returns an object with an `apply` method which then consumes the lambda that follows. That I can live with. I could live with a similar issue inside the lambda as well, so things like `decl 'Real 'x` or `decl('Real,'x)` on the inside. But what I want to do is to get the results of all those expressions inside the squiggly braces to get "returned" as a list. In other words, what I want is to write something like this: ``` model 'Foo { decl('Real,'x); decl('Real,'y); } ``` where `decl(...)` evaluates to something of type `Declaration` and the `{...}` then evaluates to `List[Declaration]`. I suspect there is some way of using implicits to do this, but I haven't been able to find it. In short, I'd like to make: ``` model 'Foo { decl('Real,'x); decl('Real,'y); } ``` ...evaluate to the equivalent of... ``` model 'Foo { decl('Real,'x) :: decl('Real,'y) :: Nil } ``` Comments or suggestions?

Original source