[英]infer a common supertype based on a parameter value and function parameter types
Should the following be compiled without needing an explicit type definition on this
? 是否应编译以下内容而不需要this
进行显式类型定义?
def prepList[B >: A](prefix: PlayList[B]) : PlayList[B] =
prefix.foldr(this: PlayList[B])((node, suffix) => suffix.prepNode(node))
It seems to me that the type should be able to inferred. 在我看来,这种类型应该能够推断出来。 Is this just a limitation in the Scala compiler, or is there a type-theoretic reason that this cannot be done? 这仅仅是Scala编译器的一个限制,还是存在类型理论上无法做到这一点的原因? I don't really have a feel yet for what the Scala type inferencer can be expected to handle. 我还没有真正意识到Scala类型推理器可以处理的内容。
Working through that method: 通过该方法:
B >: A
by definition B >: A
的定义 this
has type PlayList[A]
, which is a subtype of PlayList[B]
since B >: A
and PlayList is covariant in A
. this
具有类型PlayList[A]
,其是PlayList[B]
的子类型,因为B >: A
和PlayList在A
是协变A
。 node
has type B
, the parameter type of prefix
. node
有B
类, prefix
的参数类型。 f
in foldr
has the same type (declared B
) as the first parameter to foldr
. 第二个参数为函数参数f
在foldr
具有相同类型(声明B
)作为第一参数foldr
。 suffix
has the same type as this
, so in particular it is a PlayList[A]
. 因此suffix
具有相同的类型this
,因此在特别是一个PlayList[A]
Since B >: A
, suffix.prepNode()
takes a B
. 由于B >: A
, suffix.prepNode()
取B
I would like the compiler to see that suffix.prepNode(node)
is legal where node
has type B
. 我希望编译器看到suffix.prepNode(node)
是合法的,其中node
具有类型B
It appears to be able to do this only if I explicitly specify a type on the invocation of foldr
or on the reference to this
in that invocation. 它似乎只有在我调用foldr
或在该调用的引用上显式指定类型时才能执行this
。
Interestingly, if I specify explicit types on the function parameters as (node: B, suffix: PlayList[B])
, a type mismatch error is still generated on the parameter to the method call suffix.prepNode(node)
: "found: B, required: A"
有趣的是,如果我在函数参数上指定显式类型为(node: B, suffix: PlayList[B])
,则仍会在方法调用suffix.prepNode(node)
的参数上生成类型不匹配错误: "found: B, required: A"
I'm using Scala 2.8 RC6. 我正在使用Scala 2.8 RC6。 Full example below, the line in question is line 8. 下面的完整示例,有问题的行是第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))
}
EDIT: second attempt to reason through the compilation steps 编辑:第二次尝试通过编译步骤推理
foldr
takes parameters of types (T)((U, T) => T)
. 为了清晰起见,重命名, foldr
采用类型(T)((U, T) => T)
。 We're trying to infer the values of types U
and T
. 我们试图推断出类型U
和T
的值。 foldr
and the second parameter to the function - they're the same thing, T
. 第一个参数到foldr
和函数的第二个参数之间有一个关系 - 它们是相同的东西, T
。 (In partial answer to Daniel.) (部分回答丹尼尔。) this: PlayList[A]
and suffix: PlayList[B]
我们作为参数传递的对象的类型是this: PlayList[A]
和suffix: PlayList[B]
B >: A
, the most specific common super type is PlayList[B]
; 因此,由于B >: A
,最具体的常见超类型是PlayList[B]
; therefore we have T == PlayList[B]
. 因此我们有T == PlayList[B]
。 Note that we don't need any relationship between U
and T
to deduce this. 请注意 ,我们不需要U
和T
之间的任何关系来推断它。 This is where I get stuck: 这是我被卡住的地方:
node
has type B
(that is, U == B
). 从编译错误消息中,推理器清楚地认为node
具有类型B
(即, U == B
)。 U == B
without inferring it from the type parameter of suffix
. 我无法看到如何得出U == B
的结论,而不是从suffix
的类型参数推断它。 (Can the scala compiler do this?) (scala编译器可以这样做吗?) U == B
, and we've compiled successfully. 如果推断的步骤是发生的,那么它遵循U == B
,并且我们已成功编译。 So which step went wrong? 那一步出了什么问题? EDIT 2: In renaming the foldr
parameter types above I missed that U == A
by definition, it's the type parameter of the PlayList
class. 编辑2:在重命名上面的foldr
参数类型时,我错过了U == A
的定义,它是PlayList
类的类型参数。 I think this is still consistent with the above steps though, since we're calling it on an instance of PlayList[B]
. 我认为这仍然与上述步骤一致,因为我们在PlayList[B]
的实例上调用它。
So at the call site, T == PlayList[B]
as the least common super-type of a couple of things, and U == B
by definition of foldr
on the receiver. 所以在呼叫站点, T == PlayList[B]
作为几个事物的最不常见的超类型,并且U == B
根据接收器上的foldr
的定义。 That seems concise enough to narrow down to a couple of options: 这似乎足够简洁,可以缩小到几个选项:
B
编译器无法解析那些多种类型并计算B
的上限 PlayList[B]
of foldr
to type of parameter of prepNode
(skeptical) 错误在从返回类型获得PlayList[B]
的foldr
输入的参数的prepNode
(怀疑) I'm no type expert but here is what happens when I try to infer. 我不是类型专家,但是当我试图推断时会发生这种情况。
((node, suffix) => suffix.prepNode(node))
returns some unknown type PlayList[T]
, where T extends A . ((node, suffix) => suffix.prepNode(node))
返回一些未知类型的PlayList[T]
,其中T扩展为A. It is passed as an argument to foldr which returns the type of the function that was passed to it ( PlayList[T]
where T extends A). 它作为参数传递给foldr,它返回传递给它的函数的类型( PlayList[T]
,其中T扩展A)。 And this is supposed to be of some type PlayList[B]
. 这应该是某种类型的PlayList[B]
。
So my guess is that this:PlayList[B]
is necessary to indicate that T and B are related. 所以我的猜测是this:PlayList[B]
是必要的,表明T和B是相关的。
May be you need to have PlayList be parametric in two types PlayList[+A, B >: A]
as you have prepNode and propList that seem to work on the same type that extends A? 可能你需要让PlayList在两个类型PlayList[+A, B >: A]
参数化,因为你有prepNode和propList似乎在扩展A的相同类型上工作吗?
Said differently, your original class definition could have been defined like this: 换句话说,您的原始类定义可能已定义如下:
def prepNode[T >: A](b: T): PlayList[T]
def prepList[U >: A](prefix: PlayList[U]): PlayList[U]
But you used B in both cases and the compiler doesn't know that T and U are the same. 但是你在两种情况下都使用了B,并且编译器不知道T和U是相同的。
Edit, you can play around with the -explaintypes option and see what the compiler does depending on type hints you get. 编辑,您可以使用-explaintypes选项,并根据您获得的类型提示查看编译器的功能。 Here is the output of explaintypes and removing the :PlayList[B]
(with 2.8.0.RC1): 这是explaintypes的输出并删除:PlayList[B]
(2.8.0.RC1):
$ scalac -explaintypes -d classes Infer.scala
found : node.type (with underlying type B)
required: A
prefix.foldr(this)((node, suffix) => suffix.prepNode(node))
^
node.type <: A?
node.type <: Nothing?
B <: Nothing?
<notype> <: Nothing?
false
Any <: Nothing?
<notype> <: Nothing?
false
false
false
false
B <: A?
B <: Nothing?
<notype> <: Nothing?
false
Any <: Nothing?
<notype> <: Nothing?
false
false
false
Any <: A?
Any <: Nothing?
<notype> <: Nothing?
false
false
false
false
false
Hope this helps shed some light. 希望这有助于解决问题。 May be a question around when scalac can infer and when it cannot infer would be helpful. 可能是一个关于scalac可以推断出来的问题以及什么时候无法推断它会有所帮助。
The problem is that foldr
does not specify B >: A
, so, as far as foldr
is concerned, there is no relationship between it's own A
and B
types. 问题是foldr
没有指定B >: A
,因此,就foldr
而言,它自己的A
和B
类型之间没有关系。 As far as foldr
is concerned, suffix
and node
are completely unrelated -- even though you happen to have passed related parameters to it. 就foldr
而言, suffix
和node
完全不相关 - 即使您碰巧已经将相关参数传递给它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.