Несоответствие типов в абстрактном типе, используемом при сопоставлении с образцом - PullRequest
0 голосов
/ 24 сентября 2018

Этот код компилируется с ошибкой:

def f1[T](e: T): T = e match {
  case i:Int => i
  case b:Boolean => b
}
// type mismatch;
// found   : i.type (with underlying type Int)
// required: T
// case i:Int => i ...

И этот код, реализующий GADT, выглядит довольно идентично с точки зрения проверки типов, но компилируется без ошибок:

sealed trait Expr[T]
case class IntExpr(i: Int) extends Expr[Int]
case class BoolExpr(b: Boolean) extends Expr[Boolean]

def eval[T](e: Expr[T]): T = e match {
  case IntExpr(i) => i
  case BoolExpr(b) => b
}

В обоих случаях внутриВыражение соответствия шаблону мы знаем, что i и b являются Int и Boolean .Почему компиляция не удалась на первом примере и удалась на втором?

Ответы [ 3 ]

0 голосов
/ 24 сентября 2018

В дополнение к ответу @Esardes, это работало путем определения типа, связанного с T:

scala> def f1[T >: AnyVal](e: T):T = e match {
     |   case i:Int => i
     |   case b:Boolean => b
     | }
f1: [T >: AnyVal](e: T)T

scala> f1(1)
res3: AnyVal = 1

scala> f1(true)
res4: AnyVal = true
0 голосов
/ 24 сентября 2018

Первый случай несостоятельный, потому что вы недооцениваете разнообразие типов в системе типов Scala.Это имело бы смысл, если бы, когда мы взяли ветку case i:Int, мы знали, что T было Int, или, по крайней мере, супертип Int.Но это не должно быть!Например, это может быть 42.type или теговый тип .

Во втором случае такой проблемы нет, потому что из IntExpr <: Expr[T] компилятор знает , что T должно быть точно Int.

0 голосов
/ 24 сентября 2018

Вы просите, чтобы ваша функция возвратила тип T, затем ваш шаблон сопоставляется с Int и Boolean.За исключением того, что ваша функция не имеет доказательств того, что Int и Boolean также имеют тип T: при сопоставлении с шаблоном вы вводите ограничение , что Int <: T и Boolean <: T.Вы можете либо заменить тип возвращаемого значения T на фиксированный тип, такой как String, и вернуть строку, либо ввести ограничение, которое будет удовлетворять как Int, так и Boolean.

//this compiles
def f1[T](e: T ): String = e match {
  case _:Int => "integer"
  case _:Boolean => "boolean"
}

//this compiles too, but will return AnyVal
def f1[T >: AnyVal](e: T ): T = e match {
   case i:Int => i
   case b:Boolean => b
}

По сути, вы не можете просто динамически возвращать любой тип T, потому что вам нужно доказать во время компиляции, что ваша функция проверяет тип.

Другая функция в вашем примере устраняет проблему, инкапсулируя ограничения типов внутри caseклассы IntExpr <: Expr[Int] и BoolExpr <: Expr[Boolean] (обратите внимание, что Expr[_] будет эквивалентно T в ограничениях, которые я упомянул выше).Во время компиляции T правильно идентифицируется во всех case с (например, в IntExpr вы знаете это Int)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...