Votre problème n'est pas directement takeWhile
, mais la compréhension de la liste.
[x | x <- primes, n `mod` x == 0]
Pour n = 24
, nous obtenons 24 `mod` 2 == 0
et 24 `mod` 3 == 0
, de sorte que la valeur de cette compréhension de la liste commence par 2 : 3 : ...
. Mais considérons la partie ...
.
La compréhension de la liste doit continuer à tirer des valeurs de primes
et de vérifier 24 `mod` x == 0
. Comme il n'y a plus de facteurs premiers de 24
, rien ne passera jamais ce test et sera émis comme la troisième valeur de la compréhension de la liste. Mais puisqu'il y a toujours un autre prime à tester, il ne s'arrêtera jamais et conclura que le reste de la liste est vide. Parce que cela est évalué paresseusement, si vous demandez seulement les deux premiers éléments de cette liste, alors tout va bien. Mais si votre programme a besoin d'un troisième élément (ou même juste pour savoir s'il y a ou un troisième élément), alors la compréhension de la liste tournera pour toujours en essayant d'en trouver une.
takeWhile (< 24)
conserve les éléments de son argument jusqu'à ce qu'il en trouve un autre que < 24
. 2
et 3
tous les deux passer ce test, donc takeWhile (< 24)
besoin de savoir ce que le troisième élément de la compréhension de la liste est.
Mais ce n'est pas vraiment un problème avec takeWhile
; le problème est que vous avez écrit une liste de compréhension pour trouver tous les facteurs premiers (et rien d'autre), puis essayez d'utiliser un filtre sur les résultats de cela pour couper l'exploration infinie de tous les nombres premiers supérieurs qui ne peut pas être des facteurs.Cela n'a pas vraiment de sens si vous arrêtez d'y penser; par définition tout ce qui n'est pas un facteur premier ne peut pas être un élément de cette liste, donc vous ne pouvez pas filtrer les non-facteurs plus grands que n
de cette liste. Au lieu de cela, vous devez filtrer l'entrée à la compréhension de cette liste afin qu'elle n'essaie pas d'explorer un espace infini, comme le montre la réponse de @ n.m.
Notez que la liste '' [x | x <- nombres premiers, 10 'mod' x == 0]' 'est _not_' [2,5] ', mais quelque chose comme' 2: 5: infiniteLoop', car apr'es '5' infiniment plusieurs nombres premiers' x' seront essayé car ils pourraient passer le test. Bien sûr, nous savons qu'ils ne le feront pas, mais la compréhension de la liste ne le sait pas. Alors 'takeWhile' est coincé dans la boucle. – chi
@chi Oui, je suis conscient que ce sera une liste infinie, merci. Mais je pensais que 'takeWhile' arrêterait d'évaluer la liste infinie quand le prédicat ne tient plus. –
Non. Ce n'est pas une liste infinie. Sur ce 'takeWhile' n'aurait aucun problème. Essayez 'takeWhile (<= 10) [1 ..]' et 'takeWhile (<= 10) (1: 2: 5: soit f n = f (n + 1) dans f 3)'. Ici '[1 .. ]' est une liste infinie, tandis que' 1: 2: 5: ... 'ne l'est pas - c'est une liste avec une colonne vertébrale indéfinie après son 3ème élément. Dans une liste infinie, 'take n list' retournera toujours, à la place, lorsque la colonne vertébrale n'est pas définie, elle ne le sera pas. – chi