Differenza tra inferenza di tipo del metodo e parametri del tipo di classe nella corrispondenza del modello


9

Perché la corrispondenza dei modelli funziona in modo diverso quando il parametro type proviene da un metodo che racchiude in contrapposizione a una classe che lo racchiude? Per esempio,

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

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

dà errore

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

mentre compila correttamente quando Aè il parametro del tipo di metodo

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

La domanda si basa sull'analisi di Daniel , che ho usato per tentare di fornire una risposta a una domanda simile.

Risposte:


4

Non ho la risposta completa al 100%, ma ho un puntatore che potrebbe essere sufficiente per te.

Il compilatore Scala si occupa dei GADT (tipi di dati algebrici generalizzati) in un modo molto particolare. Alcuni casi sono risolti con una gestione speciale, alcuni casi sono irrisolti. Dotty sta cercando di colmare la maggior parte dei buchi, e ha già risolto molti problemi correlati, tuttavia ce ne sono ancora alcuni aperti .

Un tipico esempio di gestione GADT speciale nel compilatore Scala 2 è molto correlato al tuo caso d'uso. Se diamo un'occhiata a:

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

e dichiariamo esplicitamente che il tipo restituito è A:

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

compilerà bene. Il tuo IDE potrebbe lamentarsi, ma il compilatore lo farà passare. Il metodo dice che restituisce un A, ma il caso di corrispondenza del modello viene valutato in un Int, che teoricamente non dovrebbe essere compilato. Tuttavia, la gestione speciale dei GADT nel compilatore dice che va bene, perché in quel particolare ramo di corrispondenza del modello Aè stato "riparato" per essere un Int(perché abbiamo abbinato suDerived quale è unBase[Int] ).

Il parametro di tipo generico per GADT (nel nostro caso A) deve essere dichiarato da qualche parte. Ed ecco la parte interessante: la gestione speciale del compilatore funziona solo quando viene dichiarata come parametro di tipo del metodo allegato . Se proviene da un membro del tipo o da un parametro del tipo del tratto / classe allegato, non si compila, come hai visto tu stesso.

Questo è il motivo per cui ho detto che non è una risposta completa al 100%: non posso indicare un luogo concreto (come una specifica ufficiale) che lo documenti correttamente. Le fonti sulla gestione dei GADT in Scala si riducono a un paio di blogposts , che sono comunque eccezionali, ma se vuoi qualcosa di più dovrai scavare tu stesso nel codice del compilatore. Ho provato a fare esattamente questo, e penso che dipenda da questo metodo , ma se vuoi davvero andare più in profondità, potresti voler fare un ping a qualcuno più esperto con la base di codice del compilatore Scala.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.