2012-08-14 3 views
3

Quel est le type général de fs?Type de retour de la fonction récursive

lazy val fs = List(2,3,4).zip(fs.tail) 

Le compilateur demande de le définir au moment de la compilation.

Mise à jour: je voulais envisager une solution du 2ème problème Euler projet:

lazy val fs: Stream[Int] = 
     0 #:: 1 #:: fs.zip(fs.tail).map(p => p._1 + p._2) 

    fs.view.takeWhile(_ <= 4000000).filter(_ % 2 == 0).sum 

Je voulais juste déboguer ce qui se passe à ces étapes

Répondre

5

il y a un type plus précis qui le décrire. Bien sûr, il ne peut pas être calculé, donc le type réel serait Nothing.

Si nous oublions la canBuildFrom implicite, la signature de zip en List[A] serait

def zip[B](l: List[B]) : List[(A,B)] 

commençant par A = Int, il est clair que nous avons un List[(Int, B)], sans même considérer que l'argument de zip est fs.tail. Si nous ajoutons cette connaissance, nous avons maintenant List[(Int, (Int, B))] et nous pouvons faire une boucle à partir de là, vous pouvez le taper List[(Int,(Int, (Int, _)))] et imbriquer autant de niveaux que vous le souhaitez.

Je crois qu'il n'y a aucun moyen d'exprimer ce type le plus précis (imbriquant à l'infini) en scala. Quoi qu'il en soit, il n'est pas habité, ce type ne contient aucune valeur, et fs ne peut pas être calculé.

+0

@ZoltanHamori Je ne suis pas convaincu que ce soit vrai. Vois ma réponse. –

+0

Je suis d'accord que vous ne pouvez pas le taper Rien, et était au courant de cela (j'avais essayé, aurait dû le mentionner).Je crois que la raison en est que tandis que Nothing est un sous-type de n'importe quel type, il n'y a aucun membre que vous pouvez appeler (ce qui en fait un sous-type plutôt spécial). Je voulais dire taper Nothing comme le type de quelque chose qui va boucler pour toujours (ou déborder la pile). J'aurais dû être plus précis. –

+0

Ouais 'Nothing' est spécial, mais la raison pour laquelle il est impossible de taper le résultat' Nothing' est que le compilateur nécessite un 'List' et' Nothing' n'est pas un 'List' il n'a rien (sans jeu de mots;) faire ce que les membres de 'Nothing' sont. –

2

Les compiles suivants, mais l'accès fs génère un StackOverflowError en raison des définitions recursize nature.

lazy val fs:List[Product] = List(2,3,4).zip(fs.tail) 

Si nous voulions être plus précis sur le type que nous pourrions faire quelque chose comme:

lazy val fs:List[(Int, (Int, Product))] = List(2,3,4).zip(fs.tail) 

Le typle n'est pas Nothing. Étant donné que le suivant ne compile pas:

scala> lazy val fs:Nothing = List(2,3,4).zip(fs.tail) 
<console>:8: error: value tail is not a member of Nothing 
    lazy val fs:Nothing = List(2,3,4).zip(fs.tail) 

erreurs de type similaires se produisent si nous définissons fs comme List[Nothing], List[(Int, Nothing)] etc etc Donc clairement le type de l'expression est un List de Product. Maintenant, si nous utilisons Stream au contraire, nous pouvons faire quelque chose qui ne provoque pas une erreur d'exécution: Je ne pense pas

scala> lazy val fs:Stream[Any] = 0 #:: 1 #:: fs.zip(fs.tail).map(p => p:Any) 
fs: Stream[Any] = <lazy> 

scala> fs take 5 foreach println 
0 
1 
(0,1) 
(1,(0,1)) 
((0,1),(1,(0,1))) 
0

Je ne pense pas que cela soit possible dans un type moyen sûr, regardez:

scala> lazy val fs=List(1,2,3).zip(fs.tail) 
<console>:7: error: recursive lazy value fs needs type 
     lazy val fs=List(1,2,3).zip(fs.tail) 
           ^

scala> lazy val fs:List[(Int,Int)]=List(1,2,3).zip(fs.tail) 
<console>:7: error: type mismatch; 
found : List[(Int, (Int, Int))] 
required: List[(Int, Int)] 
     lazy val fs:List[(Int,Int)]=List(1,2,3).zip(fs.tail) 

Au moins je ne vois pas comment obtenir un résultat utile. Quelle est votre intention?

D'autre part, nous pouvons le faire:

scala> val l = List(1,2,3) 
l: List[Int] = List(1, 2, 3) 

scala> val fs = l.zip(l.tail) 
fs: List[(Int, Int)] = List((1,2), (2,3)) 

Est-ce votre résultat désiré?

Questions connexes