DSL的隐含参数“链接”

时间:2015-08-27 15:16:15

标签: scala dsl

我有一个想法(模糊),以这种方式传递(或链接)一些隐式值,而不是引用阻止f的参数:

def block(x: Int)(f: => Unit)(implicit v: Int) = {
  implicit val nv = v + x
  f
}

def fun(implicit v: Int) = println(v)

如果我使用了类似的东西:

implicit val ii: Int = 0
block(1) {
  block(2) {
    fun
  }
}

会打印3

如果我可以说def block(x: Int)(f: implicit Int => Unit)

换句话说,我正在寻找一些允许我实现这个DSL的设计模式:在嵌套块中访问一些累积值但是没有明确地将它作为参数传递。可能吗? (implicit s不是必需的,只是提示强调我不想明确地传递那个累加器)。当然,上面的代码将打印为0。

编辑:可能的用法之一:以下列方式编写http路由

prefix("path") {
  prefix("subpath") {
    post("action1") { (req, res) => do action }
    get("action2") { (req, res) => do action }
  }
}

此处postget会访问(如何?)累积前缀,例如List("path", "subpath")"/path/subpath/"

2 个答案:

答案 0 :(得分:3)

考虑使用DynamicVariable。它非常简单易用,而且是线程安全的:

val acc: DynamicVariable[Int] = new DynamicVariable(0)

def block(x: Int)(f: => Unit) = {
  acc.withValue(acc.value + x)(f)
}

def fun = println(acc.value)

答案 1 :(得分:1)

通过implicit传递状态很脏,会导致意外且难以追踪错误。您要求做的是构建一个函数,该函数可以通过以下方式组合:嵌套调用在某些操作上累积,而其他任何东西都使用该值来执行函数?

case class StateAccum[S](init: S){
  val op: S => S
  def flatMap[A <: S](f: S => StateAccum[A]) ={
    val StateAccum(out) = f(s)
    StateAccum(op(init, out))
  }
  def apply(f: S => A) = f(init)
}

这可以让您完全按照自己的方式进行操作,只需稍微调整一下即可。

现在,如果你真的想要嵌套的控制结构,你的apply必须使用一个隐式值来区分返回的类型,以便它将函数应用于一个而flatMap到{{1} }返回。它变得疯狂,但看起来如下:

StateAccum