Scala-如何定义一个自我引用的结构类型?

8

我正在尝试编写一个通用的interpolate方法,它适用于任何具有两个方法*+的类型,如下所示:

trait Container {
  type V = {
    def *(t: Double): V
    def +(v: V): V
  }

  def interpolate(t: Double, a: V, b: V): V = a * (1.0 - t) + b * t
}

这个方法在 Scala 2.8.0.RC7 中不可用,会出现以下错误信息:

<console>:8: error: recursive method + needs result type
           def +(v: V): V
                        ^
<console>:7: error: recursive method * needs result type
           def *(t: Double): V
                             ^

我该如何正确指定结构类型?(或者有更好的方法吗?)

http://www.scala-notes.org/2010/06/avoid-structural-types-when-pimping-libraries/ 可能对此有所帮助。 - VonC
@VonC 谢谢...那是我的个人博客! ;-) - Jesper
© 2010 Jesper de Jong……没错。好吧,对此感到抱歉 ;) - VonC
2个回答

9

你可以使用类型类(例如Scalaz)的方法来解决这个问题:

trait Multipliable[X] {
  def *(d : Double) : X
}

trait Addable[X] {
    def +(x : X) : X
}

trait Interpolable[X] extends Multipliable[X] with Addable[X]

def interpolate[X <% Interpolable[X]](t : Double, a : X, b : X)
    = a * (1.0 - t) + b * t

显然,你需要在范围内为所有你关心的类型进行(隐式)类型类转换:
implicit def int2interpolable(i : Int) = new Interpolable[Int] {
  def *(t : Double) = (i * t).toInt
  def +(j : Int) = i + j
}

然后这个可以轻松运行:
def main(args: Array[String]) {
  import Interpolable._
  val i = 2
  val j : Int = interpolate(i, 4, 5)

  println(j) //prints 6
}

有趣的方法,但它会产生一个编译器错误:http://gist.github.com/471620 - Jesper
抱歉 - 我目前无法访问可用的REPL。这种方法应该可以运行,可能只需解决一些小问题! - oxbow_lakes
看起来问题与两个术语 a * (1.0 - t)b * t 都产生了一个 X 有关,然后你正在执行 X + X 而不是 Interpolable[X] + Interpolable[X],由于某种原因,隐式的 + 没有被调用。 - Jesper
啊,可能是因为编译器决定直接使用“Int + Int”。 - oxbow_lakes
已添加了对X的视图绑定,问题已得到解决。 - oxbow_lakes

3
据我所知,这是不可能的。这是我自己的第一个问题之一。

1
真的吗?这让我感到惊讶,Scala拥有如此强大的类型系统,却无法实现这个功能。谢谢。 - Jesper
@Jesper 我想我读到过与支持它有关的类型分歧问题。 - Daniel C. Sobral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接