web-dev-qa-db-fra.com

Les types d'arguments d'une fonction anonyme doivent être parfaitement connus. (SLS 8.5)

J'ai une fonction littérale

{case QualifiedType(preds, ty) =>
               t.ty = ty ;
               Some((emptyEqualityConstraintSet,preds)) }

Ce qui entraîne un message d'erreur

missing parameter type for expanded function The argument types of an anonymous function
must be fully known. (SLS 8.5) Expected type was:
? => Option[(Typer.this.EqualityConstraintSet, Typer.this.TypeRelationSet)]

J'ai regardé dans SLS 8.5 , mais je n'ai pas trouvé d'explication.

Si j'étends moi-même la fonction

{(qt : QualifiedType) =>
  qt match {case QualifiedType(preds, ty) =>
               t.ty = ty ;
               Some((emptyEqualityConstraintSet,preds)) }}

l'erreur disparaît.

(a) Pourquoi est-ce une erreur?

(b) Que puis-je faire pour y remédier?

J'ai essayé le correctif évident, qui consistait à ajouter : QualifiedType Entre le motif et le =>, mais il s'agit d'une erreur de syntaxe.


Une chose que j'ai remarquée, c'est que le contexte fait une différence. Si j'utilise la fonction littérale comme argument d'une fonction déclarée comme attendant un QualifiedType => B, Il n'y a pas d'erreur. Mais si je l'utilise comme argument pour une fonction attendant un A => B, Il y a une erreur. Je m'attends à ce que ce qui se passe ici, c'est que, comme le modèle pourrait théoriquement être appliqué à un objet dont le type est un supertype de QualifiedType, le compilateur n'est pas disposé à attribuer le type évident sans assurance que la fonction ne sera pas appliquée à tout ce qui n'est pas un QualifiedType. Ce que j'aimerais vraiment, c'est pouvoir écrire {QualifiedType( preds, ty) => ...} et avoir la même signification que \QualifiedType(preds,ty) -> ... de Haskell.

33
Theodore Norvell

Voici le SLS quote , pour le reste d'entre nous:

Le type attendu d'une telle expression doit en partie être défini. Ce doit être soit scala.Functionk[S1, . . . , Sk, R] pour certains k> 0, ou scala.PartialFunction[S1, R], où le ou les types d'argument S1,. . . , Sk doit être entièrement déterminé, mais le type de résultat R peut être indéterminé.

Sinon, vous avez répondu à votre question.

7
som-snytt

{ case X(x) => ... } est une fonction partielle, mais le compilateur ne sait toujours pas quel est votre type d'entrée, sauf qu'il s'agit d'un supertype de X. Normalement, ce n'est pas un problème car si vous écrivez une fonction anonyme, le type est connu du contexte. Mais voici comment vous pouvez fournir le type:

case class Foo(x: Int)

// via annotation
val f: Foo => Int = { case Foo(x) => x }

// use pattern matching
val f = (_: Foo) match { case Foo(x) => x }

// or more normally, write as a method
def f(a: Foo) = a match { case Foo(x) => x }
def f(a: Foo) = a.x

Comme vous l'avez probablement remarqué, l'utilisation de la fonction littéraux/correspondance de motifs est assez inutile. Il semble que dans votre cas, vous ayez juste besoin d'une méthode régulière:

def whatever(qt: QualifiedType) = {
  t.ty = qt.ty
  Some((emptyEqualityConstraintSet, qt.preds)) 
}

bien que vous devriez refactoriser pour supprimer cet état mutable.

23

Voici pourquoi je voulais utiliser un littéral de fonction et je n'aimais pas avoir à répéter le type deux fois. J'essayais de construire ma propre construction de contrôle pour prendre en compte tout le code correspondant aux options. S'il y a trop de surcharge, la construction de contrôle n'aide pas. Voici ce que je voulais faire

//This is the control construct definition
def switch[A,B]( x : Option[A], noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

//And this is an example of using it.
def foobar( qt : Option[QualifiedType]  ) = 
    switch( qt, {reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

La construction du contrôle du commutateur se compile correctement, mais l'utilisation a provoqué une erreur car le SLS dit que là où j'ai un A, je devrais avoir un "type défini". C'est parce que ce type de fonction littérale (le type avec "case") est destiné aux fonctions partielles où l'argument pourrait être légitimement n'importe quoi. Je pourrais argumenter ma fonction littéralement avec un int et ce ne serait pas une erreur de type, mais simplement une question d'échec de tous les modèles. Le compilateur a donc besoin d'informations "descendantes" pour savoir quel type j'ai l'intention pour le paramètre du "littéral de fonction étendue", c'est-à-dire ce qu'il faut mettre pour X dans ce qui suit

{(x : X) => x match {case Some(QualifiedType(preds, ty)) =>
               Some((emptyEqualityConstraintSet,preds)) } }

Je me demande pourquoi le compilateur ne peut pas utiliser le type de commutateur pour voir que je n'ai pas l'intention d'une fonction partielle, puis unifier A avec QualifiedType. Mais ce n'est pas le cas.

Quoi qu'il en soit, il ne compile pas. Mais remplacer A par Any élimine l'erreur. Le code suivant se compile en fait. Ce que je perds, c'est une vérification de type.

//This is the control construct definition
def switch[A,B]( x : Option[A], noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

//And this is an example of using it.
def foobar( qt : Option[QualifiedType]  ) = 
    switch( qt, {reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

Je serais intéressé de savoir (a) si la définition ci-dessus de commutateur peut être améliorée, et (b) s'il existe déjà une fonction de bibliothèque qui fait ce que je veux.


Ajouté après le commentaire de Luigi

Voici le code final. Oui, je pense que c'est un pli (catamorphisme).

def switch[A,B]( x : Option[A])(noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

def foobar( qt : Option[QualifiedType]  ) : Option[(EqualityConstraintSet, TypeRelationSet)] =
    switch( qt )({reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

Merci à Luigi.

4
Theodore Norvell