是否有可能(重新)绑定一个代码块内的接收器?

时间:2013-01-31 09:23:31

标签: scala dynamic compile-time scala-macros

问题

这个问题的动机是试图找到this question的解决方案。

假设您希望使用以下语法构建层次结构:

root {
  subA {
    subB("b1.1")
    subB("b1.2")
  }
}

构造DSL应该是类型安全的,也就是说,不应该将subB直接嵌套在root中,或者将subA嵌套在另一个subAroot }}。因此,我的想法是让方法subA返回定义方法subB的对象,后者又返回定义root的对象。

我现在想要的是将代码块传递给 subA { subB("b1.1") subB("b1.2") } ,即

subB
执行

以使root的调用绑定到root { r: Root => r.subA { sa: SubA => sa.subB("b1.1") sa.subB("b1.2") } } 创建的对象。基本上就像这样

r

但无需明确接收sathis

问题:重新绑定接收器,特别是隐式Dynamic - 接收器,在Scala中可能的代码块内 - 可能使用宏吗?

其他方法

This article描述了一个用于XML树的类似结构的DSL。它们的实现基于xml html { xml head { xml title "Search Links" } } 功能,生成的DSL语法如下所示:

xml

然而,这种方法需要明确的接收器(这里是对象html),更严重的是,我不认为它是类型安全的,因为它会静态地阻止你嵌套title节点内的{{1}}节点。

1 个答案:

答案 0 :(得分:0)

我不确定这是否可用,但它看起来与您编写的代码非常相似。我添加了,并将{}更改为()

trait RootElement
trait SubAElement

def root(f:(() => RootElement)*) = ???
def subA(f:(() => SubAElement)*):() => RootElement = ???
def subB(s:String):() => SubAElement = ???

root(
  subA (
    subB("b1.1"),
    subB("b1.2")
  )
)

我不确定您是如何使用它的,如果您可以使用它,我可以根据用例尝试制作更具体的版本。


修改

  

重新绑定接收器,特别是隐式的接收器,在Scala中可能的代码块内 - 可能使用宏吗?

不,据我所知,这不可能是开箱即用的。你可能会用宏来做到这一点,但我无法帮助你。我对宏观的了解有限,这告诉我这将是一次冒险。

为了在没有宏的情况下实现相同的效果,我创建了一个小例子。我已经删除了懒惰以使其更简洁。

class Root {
  def subA(subA: SubA) = {
    // do something with subA
  }
}

class SubA {
  def subB(s: String) = {
    // do something with subB
  }
}

case class RootElement(value: SubA)
case class SubAElement(value: String)

def root(rootElems: (RootElement)*): Root = {
  val r = new Root

  rootElems foreach { sub =>
    r.subA(sub.value)
  }
  r
}

def subA(subElems: SubAElement*): RootElement = {
  val sA = new SubA
  subElems foreach { sub =>
    sA.subB(sub.value)
  }
  RootElement(sA)
}

def subB(s: String): SubAElement = SubAElement(s)

root(
  subA(
    subB("b1.1"),
    subB("b1.2")
  )
)