【发布时间】:2021-03-06 00:55:25
【问题描述】:
我想知道是否有人可以解释下面这个特殊情况下的推理规则,最重要的是它是理性/暗示?
case class E[A, B](a: A) // class E
E(2) // E[Int,Nothing] = E(2)
请注意,我可以写 E[Int](2)。对我来说重要的是为什么第二个参数类型被推断为Nothing(即底部类型)而不是说Any?为什么会这样?原因是什么?
只是为了给出一些上下文,这与 Either 的定义以及它对 Left 和 Right 的工作方式有关。两者都是根据模式定义的
final case class X[+A, +B](value: A) extends Either[A, B]
你在哪里实例化它,比如Right[Int](2),推断的类型是Right[Nothing, Int],扩展名为Either[Nothing, Int]
编辑1
这里有一致性,但我仍然可以找出理性。以下是具有逆变参数的相同定义:
case class E[A, -B](a: A)// class E
E(2) // E[Int, Any] = E(2)
因此,当它是逆变的时,我们确实有相同的东西,这使得所有行为或推理规则一致。但是我不确定这样做的合理性....
为什么不使用相反的规则,即在 Co-Variant/Invariant 时推断 Any 而在 Contra-Variant 时推断 Nothing?
编辑2
根据@slouc 的回答,这很有意义,我仍然理解编译器在做什么以及为什么要做它正在做的事情。下面的例子说明了我的困惑
val myleft = Left("Error") // Left[String,Nothing] = Left(Error)
myleft map { (e:Int) => e * 4} // Either[String,Int] = Left(Error)
- 首先,编译器将类型修复为“肯定有效”以重用@slouc 的结论(尽管在函数的上下文中更有意义)
Left[String,Nothing] - 接下来编译推断
myleft的类型为 Either[String,Int]
给定的地图定义def map[B](f: A => B): Either[E, B],只有当myleft实际上是Left[String,Int]或Either[String,Int]时才能提供(e:Int) => e * 4
也就是说,我的问题是,如果要稍后更改,将类型固定为Nothing 有什么意义。
确实以下不编译
val aleft: Left[String, Nothing] = Left[String, Int]("Error")
type mismatch;
found : scala.util.Left[String,Int]
required: Left[String,Nothing]
val aleft: Left[String, Nothing] = Left[String, Int]("Error")
那么我为什么要推断一个类型,这通常会阻止我对该类型的变量做任何其他事情(但肯定会在推断方面起作用),最终改变那个类型,所以我可以对推断类型的变量做一些事情。
EDIT3
Edit2 有点误会,@slouc answer 和 cmets 中都说明了一切。
【问题讨论】:
-
谢谢你,我看到它触及了重点,但不知怎的,我无法很好地连接它。
-
这是我没有将问题标记为重复的方式,而是在此处发布为仅供参考。
-
我真的不明白你的意思是你以后必须改变它,或者为什么你说它会阻止你对它做任何事情? - 我也不明白你认为什么会更好以及为什么。 - 最后,我不确定你是否意识到,因为 Scala 是一种急切的语言,我们必须推断每个值 的所有类型(这在 Scala 3 中会有所改变b> 具有多态函数),而在 Haskell 中,类型在使用时保持开放以进行推断,请注意,在 Scala 中不同的另一个原因是子类型 (AFAIK Haskell 没有)
-
最后,你通常没有 Nothing 类型的值,而是用来简化多个值在正确类型中的组合。
标签: scala generics type-inference covariance