1

Récemment, j'ai joué avec la programmation au niveau du type à Scala, et a trouvé ce qui suit:Pourquoi ce code Scala se bloque si vous spécifiez type-paramètre?

trait NextPage[Curr, Next] { 
    def next : Next 
} 

class Foo 
class Bar 

class X(val year : Int) 

object X { 
    implicit def xToNextPage[Y](x : X) : NextPage[X, Y] = 
    if (x.year == 2010) { 
     new X(x.year) with NextPage[X, Bar] { 
     def next = new Bar 
     } 
    } 
    else { 
     new X(x.year) with NextPage[X, Foo] { 
     def next = new Foo 
     } 
    } 
} 

val x = new X(2010) 
val y = x.next //BOOM! 

La dernière ligne se fige l'interprète indéfiniment. Ce qui est étrange, que si vous changez juste une ligne de code suivante:

implicit def xToNextPage[Y](x : X) : NextPage[X, Y] = 

que

implicit def xToNextPage(x : X) : NextPage[X, _] = 
calcul

sera effectué avec succès (mais le type résultant sera perdu, bien sûr).

Avez-vous une idée pourquoi c'est le cas? Je crois, que c'est lié à l'inférence de type en quelque sorte ...

Répondre

2

Eh bien la cause est qu'il est en récursion infinie, grâce à la conversion implicite. Retirer implicit mot-clé de xToNextPage et il affiche une erreur:

<console>:29: error: type mismatch; 
found : X with NextPage[X,Bar] 
required: NextPage[X,Y] 
      new X(x.year) with NextPage[X, Bar] { 

Il est évident que votre déclaration de fonction dit que vous revenez NextPage[X, Y] mais vous revenez en fait NextPage[X,Any].

Il va en récursivité parce que lorsqu'il est marqué comme implicit parce que votre type de retour de fonction est de [X, Y]. Mais comme vous renvoyez [X,Any], il appelle à nouveau la fonction implicite xToNextPage pour essayer de le convertir.

Solution: Modifier déclaration:

trait NextPage[Curr, +Next] { 
    def next : Next 
} 
implicit def xToNextPage[Y](x : X) : NextPage[X, Any] 
0

Je ne suis pas sûr de ce que vous essayez d'accomplir ici. Je n'ai pas vraiment d'expérience avec la programmation de niveau type dans Scala, mais cela ne me semble pas être une programmation correcte au niveau du type. Qu'est-ce que vous essayez exactement d'atteindre avec le paramètre de type Y dans xToNextPage[Y](x : X)? La seule valeur possible pour Next[X, Y] est Next[X, AnyRef], puisque l'ancêtre le moins commun de Foo et Bar est AnyRef. Se débarrasser de la Y vous donne la seule réponse correcte:

trait NextPage[Curr, Next] { 
    def next : Next 
} 

class Foo 
class Bar 

class X(val year : Int) 

object X { 
    implicit def xToNextPage(x : X) = 
    if (x.year == 2010) { 
     new X(x.year) with NextPage[X, Bar] { 
     def next = new Bar 
     } 
    } 
    else { 
     new X(x.year) with NextPage[X, Foo] { 
     def next = new Foo 
     } 
    } 
} 

val x = new X(2010) 
val y = x.next // => y: Object = [email protected] 

Je ne pense pas que cela répond vraiment à votre question, mais je pense que cela pourrait aider un peu. Je serais intéressé de voir si quelqu'un d'autre peut trouver une solution qui infère effectivement y: Bar, mais je pense que c'est au-delà des limites du système de type.

Questions connexes