PartialFunction orElse 的类型界限是否比它应该的更宽松? [英] Is PartialFunction orElse looser on its type bounds than it should be?

查看:44
本文介绍了PartialFunction orElse 的类型界限是否比它应该的更宽松?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们定义一个 PartialFunction[String, String] 和一个 PartialFunction[Any, String]

Let's define a PartialFunction[String, String] and a PartialFunction[Any, String]

现在,给定orElse

def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] 

我希望不能将两者组合起来,因为

I would expect not to be able to compose the the two, since

A字符串
A1任何

AString
A1Any

因此绑定的 A1 <: A(即 Any <: String)不成立.

and therefore the bound A1 <: A (i.e. Any <: String) doesn't hold.

没想到,我可以组合它们并获得在整个String域上定义的PartialFunction[String, String].举个例子:

Unexpectedly, I can compose them and obtain a PartialFunction[String, String] defined on the whole String domain. Here's an example:

val a: PartialFunction[String, String] = { case "someString" => "some other string" }
// a: PartialFunction[String,String] = <function1>

val b: PartialFunction[Any, String] = { case _ => "default" }
// b: PartialFunction[Any,String] = <function1>

val c = a orElse b
// c: PartialFunction[String,String] = <function1>

c("someString")
// res4: String = some other string

c("foo")
// res5: String = default

c(42)
// error: type mismatch;
//   found   : Int(42)
//   required: String

此外,如果我明确提供了 orElse 类型参数

Moreover, if I explicitly provide the orElse type parameters

a orElse[Any, String] b
// error: type arguments [Any,String] do not conform to method orElse's type parameter bounds [A1 <: String,B1 >: String]

编译器终于显示了一些意义.

the compiler finally shows some sense.

是否有任何我遗漏的类型系统魔法导致 b 成为 orElse 的有效参数?换句话说,为什么 A1 被推断为 String ?

Is there any type system sorcery I'm missing that causes b to be a valid argument for orElse? In other words, how come that A1 is inferred as String?

如果编译器从 b 推断出 A1 那么它必须是 Any,那么导致 的推理链在哪里字符串开始?

If the compiler infers A1 from b then it must be Any, so where else does the inference chain that leads to String start?

在玩过 REPL 后,我注意到 orElse 在类型不匹配时返回一个交集类型 A with A1.示例:

After playing with the REPL I noticed that orElse returns an intersection type A with A1 when the types don't match. Example:

val a: PartialFunction[String, String] = { case "someString" => "some other string" }
// a: PartialFunction[String,String] = <function1>

val b: PartialFunction[Int, Int] = { case 42 => 32 }
// b: PartialFunction[Int,Int] = <function1>

a orElse b
// res0: PartialFunction[String with Int, Any] = <function1>

由于 (String with Int) <:<String 这有效,即使结果函数实际上无法使用.我也怀疑 String with Any 统一为 Any,因为

Since (String with Int) <:< String this works, even though the resulting function is practically unusable. I also suspect that String with Any is unified into Any, given that

import reflect.runtime.universe._
// import reflect.runtime.universe._   

typeOf[String] <:< typeOf[String with Any]
// res1: Boolean = true

typeOf[String with Any] <:< typeOf[String]
// res2: Boolean = true

这就是为什么将 StringAny 结果混合到 String 中的原因.

So that's why mixing String and Any results into String.

话虽如此,引擎盖下发生了什么?错配类型统一在什么逻辑下?

That being said, what is going on under the hood? Under which logic are the mismatching types unified?

我已将问题简化为更一般的形式:

I've reduced the issue to a more general form:

class Foo[-A] {
  def foo[B <: A](f: Foo[B]): Foo[B] = f
}

val a = new Foo[Any]
val b = new Foo[String]

a.foo(b) // Foo[String] Ok, String <:< Any
b.foo(a) // Foo[String] Shouldn't compile! Any <:!< String
b.foo[Any](a) // error: type arguments [Any] do not conform to method foo's type parameter bounds [A <: String]

推荐答案

你把它搞砸了.

你总是可以向需要A类型参数的方法传递B<:A类型的任何参数,即A的任何子类型代码>.那就是如果你有

You can always pass to a method requiring a parameter of type A any argument of type B <: A, i.e. any subtype of A. That is if you have

def foo(a: Animal)

你可以传递一个 Dogfoo,因为 Dog <: Animal.

you can pass a Dog to foo, because Dog <: Animal.

同样,如果你有

def foo(l: List[Animal])

您可以将 List[Dog] 传递给它,因为 List 与其类型参数是协变的,并且因为 Dog <: Animal, 然后 List[Dog] <: List[Animal]

you can pass a List[Dog] to it, because List is covariant with its type parameter and since Dog <: Animal, then List[Dog] <: List[Animal]

现在如果你有

def foo(pf: PartialFunction[String, String])

您可以传递一个 PartialFunction[Any, String],因为 PartialFunction 与第一个类型参数是逆变的,而与第二个类型参数是协变的.由于 Any >: String,则 PartialFuncion[Any, String] <: PartialFunction[String, String].

you can pass a PartialFunction[Any, String], because PartialFunction is contravariant with the first type parameter and covariant with the second. Since Any >: String, then PartialFuncion[Any, String] <: PartialFunction[String, String].

现在,对于类型边界,编译器将尝试推断 A1B1,使得

Now, for the type bounds, the compiler will try to infer A1 and B1, such that

  • A1A
  • 的子类型
  • B2B
  • 的子类型
  • A1 is subtype of A
  • B2 is subtype of B

为此,它将寻找:

  • AnyString 的最大公共子类型,因为 AA1 处于逆变位置
  • StringString 最不常见的超类型,因为 BB1 是协变位置
  • the greatest common subtype of Any and String, since A and A1 are in contravariant position
  • the least common supertype of String and String, since B and B1 is covariant position

结果

  • A1字符串
  • B1字符串
  • A1String
  • B1String

PartialFunction[String, String] 与 PartialFunction[Int, Int] 组合在一起的情况是前一个例子的一个奇怪的情况,在其中:

The case in which you compose a PartialFunction[String, String] with a PartialFunction[Int, Int] is an odd-looking case of the previous example, in which:

  • StringInt最大的共同子类型是String with Int,即两种类型的交集,是两者的子类型(在这种情况下几乎就像在说 Nothing:both StringInt 似乎并不很有可能)
  • StringInt 最不常见的超类型是 Any
  • the greatest common subtype of String and Int is String with Int, i.e. the interesection of the two types, which is subtype of both (in this case is pretty much as saying Nothing: being both a String and an Int doesn't seem very likely)
  • the least common supertype of String and Int is Any

因此

val a: PartialFunction[String, String] = ...
val b: PartialFunction[Int, Int] = ...
a orElse b // PartialFunction[String with Int, Any] // as expected, although not very useful...

这篇关于PartialFunction orElse 的类型界限是否比它应该的更宽松?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆