我有一个相当琐碎的代数。
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返回一个函数。但是,我必须将强制类型转换回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
}
如果result
是最后一条语句,则在编译时会出现此错误。
[error] found : argonaut.Json => Any
[error] required: argonaut.Json => A
[error] result
在Cats示例中,这种语法代码样式似乎很标准,所以我不确定在这里做错了什么。
答案 0 :(得分:1)
问题似乎是Scala编译器不够聪明,无法从Json => A
/ match
的代码中自动推断出类型case
:所有返回类型都不同分支是不同的,因此推断类型Json => Any
。但是,如果必须的话,可以对这种类型进行类型检查非常聪明。因此,尝试在result
的声明中明确指定类型,如下所示:
val result: (Json => A) = kvp match {
或者删除result
变量,然后只返回整个kvp match
语句,然后编译器将尝试对方法的预期返回类型进行类型检查,并且应该也可以工作。