DSL的“更近的范围”中的隐含参数

时间:2013-11-27 01:03:30

标签: scala implicit

我正在尝试在scala中组合一个类似DSL的函数集,而我想要的是......的效果......

implicit val x = 1

doSomething()         // uses x

context { implicit y =>
  doSomething()       // uses y
  doSomethingElse()   // uses y
}

其中context是......的效果。

def context[A](f: Int => A) = f(2)

我遇到的问题是,使用此语法,scala将报告ambiguous implicit values。我有点假设,如果一个隐含的被定义在一个“更接近”的范围内,那么它将会越过更远的范围,但看起来并非如此。

有没有办法向scala发出信号,说明一个隐含的比另一个更具体(除了我认为更强的范围)?

2 个答案:

答案 0 :(得分:3)

一种可能的解决方案是将内部参数命名为与外部参数相同。

context { implicit y =>

context { implicit x =>

这可行,但不太可取。有更好的解决方案吗?

答案 1 :(得分:1)

这可能不是你想要的,但它有点相关,所以它可能会给你一些想法。

您可以对隐式类进行子类型化,并利用将选择最具体类型的事实:

scala> :paste
// Entering paste mode (ctrl-D to finish)

  class A { override def toString = "A" }
  class B extends A { override def toString = "B" }

  implicit val a = new A
  implicit val b = new B

  def foo()(implicit x: A) { println(x) }

// Exiting paste mode, now interpreting.

defined class A
defined class B
a: A = A
b: B = B
foo: ()(implicit x: A)Unit

scala> foo()
B

这里我们已经定义了foo方法来获取类型A的隐式参数。我们必须在范围ab中使用类型A的隐式val,但是{{1更具体,因此没有歧义,输出显示b被选中。

让我们试着让它适应你的例子:

b

这里的技巧是将参数中的子类型用于class A class B extends A def foo()(implicit a: A) = a def bar[U](p: B => U) { p(new B) } implicit val a = new A bar { implicit b => foo() } 方法(您的bar)。

证明它有效的一个小例子:

context

这里有两种可能的问题:B 必须扩展A,如果忘记了,它会在两种情况下都打印“A”。如果您忘记在scala> :paste // Entering paste mode (ctrl-D to finish) class A { override def toString = "A" def getB = new B } class B extends A { override def toString = "B" } def foo()(implicit a: A) { println(a) } def bar[U](p: B => U)(implicit a: A) { p(a.getB) } implicit val a = new A def test() { foo() // should print "A" bar { implicit b => foo() // should print "B" } } // Exiting paste mode, now interpreting. defined class A defined class B foo: ()(implicit a: A)Unit bar: [U](p: B => U)(implicit a: A)Unit a: A = A test: ()Unit scala> test() A B 的调用中将implicit关键字放在参数上,则类似。

您在这里获得的是能够在不同的A上调用bar不同的A值而不明确指定它们。