应该在不需要this
上的显式类型定义的情况下编译以下代码:根据参数值和函数参数类型推断出一个共同的超类型
def prepList[B >: A](prefix: PlayList[B]) : PlayList[B] =
prefix.foldr(this: PlayList[B])((node, suffix) => suffix.prepNode(node))
在我看来,类型应该能够推断。这只是Scala编译器的一个限制,还是有类型理论的原因,这是不能做到的?对于Scala类型推理者可以处理什么,我还没有感觉到。
通过该方法工作:
B >: A
通过定义this
已键入PlayList[A]
,这是PlayList[B]
亚型因为B >: A
和播放列表是在A
协变。node
有型号B
,参数类型prefix
。- 功能参数
f
的第二个参数foldr
与foldr
的第一个参数具有相同类型(声明为B
)。 - 因此
suffix
与this
具有相同的类型,所以特别是它是PlayList[A]
。由于B >: A
,suffix.prepNode()
需要B
。
我想编译器看到suffix.prepNode(node)
地区是合法的node
具有类型B
。只有在调用foldr
或在该调用中引用this
时明确指定类型,才能够做到这一点。
有趣的是,如果我在功能参数指定明确类型作为(node: B, suffix: PlayList[B])
,仍是在参数的方法调用suffix.prepNode(node)
产生的类型不匹配的错误:
我使用的Scala 2.8 RC6。下面完整的例子,所讨论的行是8行
sealed abstract class PlayList[+A] {
import PlayList._
def foldr[B](b: B)(f: (A, B) => B): B
def prepNode[B >: A](b: B): PlayList[B] = nel(b, this)
def prepList[B >: A](prefix: PlayList[B]): PlayList[B] =
// need to specify type here explicitly
prefix.foldr(this: PlayList[B])((node, suffix) => suffix.prepNode(node))
override def toString = foldr("")((node, string) => node + "::" + string)
}
object PlayList {
def nil[A]: PlayList[A] = Nil
def nel[A](head: A, tail: PlayList[A]): PlayList[A] = Nel(head, tail)
def nel[A](as: A*): PlayList[A] = as.foldRight(nil[A])((a, l) => l.prepNode(a))
}
case object Nil extends PlayList[Nothing] {
def foldr[B](b: B)(f: (Nothing, B) => B) = b
}
case class Nel[+A](head: A, tail: PlayList[A]) extends PlayList[A] {
def foldr[B](b: B)(f: (A, B) => B) = f(head, tail.foldr(b)(f))
}
编辑:第二通汇编推理尝试步骤
- 重命名为清楚起见,需要
foldr
类型(T)((U, T) => T)
参数。我们试图推断U
和T
类型的值。 - 第一个参数与
foldr
和函数的第二个参数之间有关系 - 它们是同一个东西,T
。 (在部分答案丹尼尔。) - 类型我们传递那些参数
this: PlayList[A]
和suffix: PlayList[B]
- 这样的对象,因为
B >: A
,最具体的公用超类型是PlayList[B]
;因此我们有T == PlayList[B]
。注意我们不需要U
和T
之间的任何关系来推断这一点。
这是我卡住:
- 从编译错误消息,在inferencer明确认为
node
具有类型B
(即U == B
)。 - 我看不出
U == B
如何从suffix
的类型参数中推断出它的结论。 (scala编译器可以做到这一点吗?) - 如果推理的步骤是发生了什么,那么它遵循
U == B
,我们已经成功编译。那么哪一步出错?
编辑2:在重命名foldr
参数类型以上我错过了U == A
根据定义,它是PlayList
类的类型参数。我认为这仍然与上述步骤一致,因为我们将它称为PlayList[B]
的实例。
所以在呼叫站点,T == PlayList[B]
作为最不常见的超级类型的一对事物,而U == B
的定义为foldr
。这似乎不够简洁缩小到几个选项:
- 编译器无法解决这些多种类型和计算上限
B
- 错误的,从返回类型的
foldr
PlayList[B]
键入的获得参数prepNode
(持怀疑态度)
你是对的,我正在寻找编译器来看这些应该是相同的,在某种意义上,这个调用,但总的来说T和U是不一样的:考虑这种情况下,我称之为两种方法分开。该声明中的B只是该方法范围内使用的绑定类型的名称。在这种情况下,我的理解是PlayList [B]是这个和后缀的常见超类型,因此应该被推断为两者的类型。也就是说,prepNode的形式类型参数B在该调用中应该与prepList的实际类型参数B具有相同的值。 – 2010-06-28 14:40:23
然后可能是我的建议是不正确的。不过,似乎不得不指定'this:PlayList [B]'对我来说是有意义的。 – huynhjl 2010-06-28 15:37:07