Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - omit parentheses from apply method for a DSL

Tags:

scala

apply

dsl

I'm trying to create a DSL and running into a problem. I have these definitions:

case class Var(name: String)
case class Lam(v: Var, t: Var)
val (a, b) = (Var("a"), Var("b"))

I want to be able to do this:

scala> \ a b
Lam(Var(a),Var(b))

Reading up on the rules of parenthesis dropping, I see that I need to chain functions that take one parameter each, so I've created a series of "builder" classes that perform the construction:

class LamBuilderB(v: Var) {
    def apply(t: Var) = Lam(v, t)
}

class LamBuilderA {
    def apply(v: Var) = new LamBuilderB(v)
}

val \ = new LamBuilderA

I had hoped this would work since each apply takes only one argument. But, it doesn't seem like dropping the parentheses is legal for apply since it wants to treat the argument as a method name:

scala> \(a)(b)
res95: Lam = Lam(Var(a),Var(b))

scala> \ a b
error: value a is not a member of LamBuilderA
    \ a b
      ^

Any ideas how how I can get the DSL syntax without parentheses?

Bonus Question: Can I get this?:

scala> \a.b
Lam(Var(a),Var(b))
like image 743
dhg Avatar asked Jul 21 '11 17:07

dhg


1 Answers

You can get pretty close using one of 4 unary prefix operators (~, !, +, -):

trait Expr {
    def &(other: Expr) = Lam(this, other)
    def unary_~ = this
}

case class Var(name: String) extends Expr
case class Lam(a: Expr, b: Expr) extends Expr

scala> ~ Var("a") & Var("b")
res0: Lam = Lam(Var(a),Var(b))

scala> ~ Var("a") & Var("b") & Var("c")
res1: Lam = Lam(Lam(Var(a),Var(b)),Var(c))
like image 119
Vasil Remeniuk Avatar answered Sep 27 '22 18:09

Vasil Remeniuk