Scala GADT Fantom类型解释器错误:找到任何必需的

Scala GADT Fantom类型解释器错误:找到任何必需的,scala,Scala,我有一个相当平凡的代数 sealed abstract class Kvp[A] case class KvpString(key: String) extends Kvp[String] case class KvpInt(key: String) extends Kvp[Int] case class KvpBool(key: String) extends Kvp[Boolean] case class KvpPair[A,B](p1: Kvp[A], p2: Kvp[B]) extend

我有一个相当平凡的代数

sealed abstract class Kvp[A]
case class KvpString(key: String) extends Kvp[String]
case class KvpInt(key: String) extends Kvp[Int]
case class KvpBool(key: String) extends Kvp[Boolean]
case class KvpPair[A,B](p1: Kvp[A], p2: Kvp[B]) extends Kvp[(A,B)]
我试图创建一个解释器,它从Json=>a返回一个函数。但是,我必须键入cast back to a,以便编译代码

  import argonaut._, Argonaut._

  def eval[A](kvp: Kvp[A]) : Json => A = {
    val result = kvp match {
      case KvpString(key) =>
        (json: Json) =>
          json.field(key).flatMap(_.string).get
      case KvpInt(key) =>
        (json: Json) =>
          json.field(key).flatMap(_.number).flatMap(_.toInt).get
      case KvpBool(key) =>
        (json: Json) =>
          json.field(key).flatMap(_.bool).get
      case KvpPair(p1, p2) =>
        (json: Json) =>
          (eval(p1).apply(json), eval(p2).apply(json))
    }
    result // <-- this would result in the error
    result.asInstanceOf[Json => A] // so I have to do this
 }

在Cats示例中,这种语法代码样式似乎非常标准,因此,我不确定我在这里做错了什么。

问题似乎是Scala编译器不够聪明,无法从
匹配的代码中自动推断出类型
Json=>A
:不同分支中的所有返回类型都不同,因此可以推断出类型
Json=>Any
。但是,如果有必要的话,对这样一种类型进行打字检查已经足够聪明了。因此,尝试在
结果的声明中显式指定类型,如下所示:

  val result: (Json => A) = kvp match {

或者删除
result
变量,只返回整个
kvp match
语句,然后编译器将尝试根据方法的预期返回类型进行类型检查,它也应该可以工作。

您是否忘记将
KvpPair
的类型参数限制为仅
Kvp
s?这样,最后的转换是非常不安全的。@GáborBakos这两个参数是(p1:Kvp[A],p2:Kvp[B]),因此它们必须是Kvp。然而,我认为这可能是一种更合适的编码方式:案例类KvpPair[A1,K1注意,这确实适用于scala编译器,但是Intellij(版本2018.1)将为每个Lamda实体显示一个错误,例如“Int不符合类型a”
  val result: (Json => A) = kvp match {