Scala类型推论规则对逆性?

问题描述

我正在使用Circe,发现我不太舒服,想了解引擎盖下发生了什么事?

从根本上讲,这并不是一个真正的问题。我也只是玩转来测试一些东西。因此本来可以直接JsonObject中进行解码,但这已经不重要了。

val jobjectStr = """{
    |    "idProperty": 1991264,|    "nIndex": 0,|    "sPropertyValue": "0165-5728"
    |  }""".stripMargin



val jobject = decode[Json](jobjectStr).flatMap{ json =>
    json.as[JsonObject]
}

我的问题是,Everer的flaveMap签名,逆变以及这里发生的事情:

我们有以下几种类型:

decode[Json](jobjectStr): Either[Error,Json]
json.as[JsonObject]: Decoder.Result[JsonObject]

circe定义的地方

final type Result[A] = Either[DecodingFailure,A]

sealed abstract class DecodingFailure(val message: String) extends Error {

现在flatMap的签名是:

def flatMap[A1 >: A,B1](f: B => Either[A1,B1]): Either[A1,B1]

换句话说,只谈论类型就像我的代码一样

Either[Error,Json] flatMap Either[DecodingFailure,JsonObject]

因此,我的问题是: DecodingFailure >: Error 不正确

确实,完整表达式的类型是:

decode[Json](jobjectStr).flatMap{ json =>
    json.as[JsonObject]
}: Either[Error,JsonObject]

因此,我感到困惑,因为我的理解是,flatMap签名中Either的第一个参数的类型是相反的。这里似乎有一些奇怪的最小上限推断正在发生……但是我不确定为什么或是否确实如此。

任何解释吗?

解决方法

这实际上不是差异问题。 A1 >: A只是告诉我们,如果编译器必须寻找最小的上限值,则结果类型A1可能必须是接收到的类型A的超类型。绑定(LUB)。 (我认为A1描述中使用f: B => ...有点令人困惑。)

请考虑以下内容:

class Base
class SubA extends Base
class SubB extends Base

Either.cond(true,"a string",new SubA)
  .flatMap(Either.cond(true,_,new SubB))

//res0: scala.util.Either[Base,String] = Right(a string)

请注意结果如何Either[Base,String],因为BaseSubASubB的LUB。

,

因此,首先,我们需要了解编译器将始终尝试推断允许编译的类型。避免编译的唯一真实方法是使用隐式
(不确定这是语言规范的一部分,还是编译器实现的详细信息,还是所有编译器都共有的东西,还是错误或功能)

现在,让我们从一个简单的示例列表::开始。

sealed trait List[+A] {
  def ::[B >: A](b: B): List[B] = Cons(b,this)
}

final case class Cons[+A](head: A,tail: List[A]) extends List[A]
final case object Nil extends List[Nothing]

因此,假设编译器将始终允许诸如x :: list之类的某些代码将始终进行编译。然后,我们有三种情况:

  1. x A 类型,而list List [A] ,因此很明显,返回值必须是类型为列表[A]
  2. x C 类型,而list列表[A] ,而 C A C <: A的子类型。然后,编译器简单地将x转换为 A 类型,然后该过程继续与上一个相同。
  3. x D 类型,而list列表[A] ,而 D 是不是 A 的子类型。然后,编译器找到一个新类型 B ,它是 D A 之间的LUB,编译器最后将x都转换为的类型为 B ,而list则为列表[B] (这可能是由于协方差)一个。
    另外,请注意,由于存在 Any Nothing 之类的类型,因此两种类型之间总是存在一个LUB。

现在让我们看看 flatMap

sealed trait Either[+L,+R] {
  def flatMap[LL >: L,RR](f: R => Either[LL,RR]): Either[LL,RR]
}

final case class Left[+L](l: L) extends Either[L,Nothing]
final case clas Right[+R](r: R) extends Either[Nothing,R]

现在,假设我的左侧是错误,我觉得这种在两个可能的左侧之间返回LUB的行为是最好的,因为最后我会遇到第一个错误,或者第二个错误或最终值,因此,由于我不知道这两个错误中的哪一个,因此该错误必须是某种类型,它封装了两种可能的错误。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...