Різниця між типом виводу методу та параметрами типу класу у відповідності шаблонів


9

Чому відповідність шаблонів працює по-різному, коли параметр типу походить від методу, що входить в комплект, на відміну від класу, що додає? Наприклад,

trait Base[T]
case class Derived(v: Int) extends Base[Int]

class Test[A] {
  def method(arg: Base[A]) = {
    arg match {
      case Derived(_) => 42
    }
  }
}

дає помилку

constructor cannot be instantiated to expected type;
 found   : A$A87.this.Derived
 required: A$A87.this.Base[A]
      case Derived(_) => 42
           ^

при цьому він успішно компілює, коли Aпараметр типу методу

class Test {
  def method[A](arg: Base[A]) = {
    arg match {
      case Derived(_) => 42
    }
  }
}

Питання засноване на аналізі Даніеля , який я намагався дати відповідь на подібне запитання.

Відповіді:


4

У мене немає 100% повної відповіді, але у мене є вказівник, який може бути достатнім для вас.

Компілятор Scala дуже конкретно стосується GADT (Узагальнені типи алгебраїчних даних). Деякі справи вирішуються спеціальним поводженням, деякі випадки - невирішеними. Dotty намагається заповнити більшість лунок, і це вже вирішило багато пов'язаних з цим питань, однак є ще досить багато відкритих .

Типовий приклад спеціального поводження з GADT у компіляторі Scala 2 дуже пов'язаний із вашим випадком використання. Якщо ми подивимось на:

def method[A](arg: Base[A]) = {
  arg match {
    case Derived(_) => 42
  }
}

і ми явно оголошуємо тип повернення таким A:

def method[A](arg: Base[A]): A 

вона складеться чудово. Ваш IDE може скаржитися, але компілятор відпустить це. Метод каже, що він повертає A, але випадок відповідності шаблону обчислюється в an Int, який теоретично не слід компілювати. Однак, спеціальна обробка GADT в компіляторі говорить, що це добре, тому що в цій конкретній гілці відповідності шаблону Aбуло "зафіксовано", щоб бути Int(тому що ми відповідали, на Derivedякому це а Base[Int]).

Параметр загального типу для GADT (у нашому випадку A) повинен десь бути оголошений. І ось цікава частина - спеціальний обробник компілятора працює лише тоді, коли він оголошений як параметр типу методу укладання . Якщо він надходить від типу типу або параметру типу додаючої ознаки / класу, він не компілюється, як ви свідчили самі.

Ось чому я сказав, що це не 100% повна відповідь - я не можу вказати на конкретне місце (наприклад, офіційну специфікацію), яке це правильно документує. Джерела по обробці GADTs в Scala зводяться до парі з · блоги , · , які є великими по шляху, але якщо ви хочете більше , ніж вам доведеться копатися в коді компілятор самостійно. Я спробував зробити саме це, і я думаю, що це зводиться до цього методу , але якщо ви дійсно хочете заглибитись, ви, можливо, захочете пінговувати когось більш досвідченого з кодовою базою компілятора Scala.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.