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?