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))
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))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With