DSL 的隐式参数 "chaining"
Implicit parameter "chaining" for 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
不是必需的,只是一个强调我不想显式传递该累加器的提示)。当然上面的代码会打印 0.
编辑:一种可能的用法:以下列方式组成 http 路由
prefix("path") {
prefix("subpath") {
post("action1") { (req, res) => do action }
get("action2") { (req, res) => do action }
}
}
此处 post
和 get
将访问(如何?)累积前缀,例如 List("path", "subpath")
或 "/path/subpath/"
。
通过 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)
}
这可以让您完全按照自己的意愿行事,只需稍微改变您的称呼方式即可。
现在,如果您真的想要嵌套控制结构,您的应用程序将不得不使用隐式值来区分 return 的类型,以便将函数应用于一个 flatMap
到 StateAccum
return 秒。它变得疯狂但看起来像下面这样:
def apply[A](f: S => A)(implicit mapper: Mapper[S, A]): mapper.Out = mapper(this, f)
trait Mapper[S, A]{
type Out
def apply(s: StateAccum[S], f: S => A): Out
}
object Mapper extends LowPriorityMapper{
implicit def acuum[S, A <: S] = new Mapper[S, StateAccum[A]]{
type Out = StateAccum[A]
def apply(s: StateAccum[S], f: S => StateAccum[A]) = s.flatMap(f)
}
}
trait LowPriorityMapper{
implicit def acuum[S, A] = new Mapper[S, A]{
type Out = A
def apply(s: StateAccum[S], f: S => A) = f(s.init)
}
}
考虑为此使用 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)
我有一个想法(模糊),以这种方式传递(或链接)一些隐式值,而不是将参数引入块 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
不是必需的,只是一个强调我不想显式传递该累加器的提示)。当然上面的代码会打印 0.
编辑:一种可能的用法:以下列方式组成 http 路由
prefix("path") {
prefix("subpath") {
post("action1") { (req, res) => do action }
get("action2") { (req, res) => do action }
}
}
此处 post
和 get
将访问(如何?)累积前缀,例如 List("path", "subpath")
或 "/path/subpath/"
。
通过 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)
}
这可以让您完全按照自己的意愿行事,只需稍微改变您的称呼方式即可。
现在,如果您真的想要嵌套控制结构,您的应用程序将不得不使用隐式值来区分 return 的类型,以便将函数应用于一个 flatMap
到 StateAccum
return 秒。它变得疯狂但看起来像下面这样:
def apply[A](f: S => A)(implicit mapper: Mapper[S, A]): mapper.Out = mapper(this, f)
trait Mapper[S, A]{
type Out
def apply(s: StateAccum[S], f: S => A): Out
}
object Mapper extends LowPriorityMapper{
implicit def acuum[S, A <: S] = new Mapper[S, StateAccum[A]]{
type Out = StateAccum[A]
def apply(s: StateAccum[S], f: S => StateAccum[A]) = s.flatMap(f)
}
}
trait LowPriorityMapper{
implicit def acuum[S, A] = new Mapper[S, A]{
type Out = A
def apply(s: StateAccum[S], f: S => A) = f(s.init)
}
}
考虑为此使用 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)