Est l'opérateur && stricte en Haskell?
Par exemple, j'ai une opération fnB :: a -> Bool
qui n'a pas de sens jusqu'à ce que fnA :: Bool
retourne False
. En C je peut composer ces deux opérations en une if
bloc:
if( fnA && fnB(a) ){ doSomething; }
et C permettra de garantir que fnB
ne va pas s'exécuter jusqu'à ce que fnA
renvoie la valeur false.
Mais Haskell est paresseux, et, généralement, il n'y a aucune garantie que le fonctionnement soit exécuté en premier, jusqu'à ce que nous n'utilisons pas de seq
, $!
, ou quelque chose d'autre à faire de notre code strict. Généralement, c'est ce dont nous avons besoin pour être heureux. Mais à l'aide de &&
opérateur, je m'attends à ce que fnB
ne sera pas évalué jusqu'à fnA
retourne son résultat. Ne Haskell offrir une telle garantie avec &&
? Et Haskell évaluer fnB
même lorsque fnA
renvoie False?
Vous devez vous connecter pour publier un commentaire.
La fonction
(&&)
est stricte dans son deuxième argument, que si son premier argument estTrue
. Il est toujours stricte dans son premier argument. Cette rigueur /la paresse est ce qui garantit l'ordre d'évaluation.De sorte qu'il se comporte exactement comme C. La différence est que dans Haskell,
(&&)
est une fonction ordinaire. En C, cela serait impossible.Ce n'est pas correct. La vérité est plus profond.
Cours intensif de rigueur:
Nous savons
(&&)
est stricte dans son premier paramètre car:Ici, ⊥ est quelque chose comme
undefined
ou une boucle infinie (⊥ est prononcé "en bas"). Nous savons aussi que(False &&)
est non-stricte dans son deuxième argument:Qu'il ne peut pas évaluer son deuxième argument, parce que son second argument est ⊥ qui ne peut être évalué. Cependant, la fonction
(True &&)
est stricte dans son deuxième argument, parce que:Donc, nous disons que
(&&)
est toujours stricte dans son premier argument, et à la stricte dans son deuxième argument, que lorsque le premier argument estTrue
.Ordre d'évaluation:
Pour
(&&)
, sa rigueur propriétés sont suffisantes pour garantir l'ordre d'exécution. Ce n'est pas toujours le cas. Par exemple,(+) :: Int -> Int -> Int
est toujours stricte dans les deux arguments, donc, soit l'argument peut être évaluée en premier. Cependant, vous ne pouvez faire la différence par la capture des exceptions dans leIO
monade, ou si vous utilisez ununsafe
fonction.id
est toujours stricte dans son argument.False && ⊥
ne doit pas évaluer ⊥, donc il doit évaluerFalse
premier sinon il ne serait pas savoir qu'il n'est pas censé évaluer ⊥. Donc, il n'est pas possible d'évaluerFalse && ⊥
en parallèle. Vous pouvez écrire un parallèle à mémoire partagée, programme qui donne le même résultat, si.&&
appels tail son deuxième argument, lorsque le premier estTrue
.Comme indiqué par d'autres, naturellement
(&&)
est stricte dans l'un de ses arguments. Par la définition standard, c'est la stricte dans son premier argument. Vous pouvez utiliserflip
pour inverser la sémantique.Comme une autre remarque: Notez que les arguments de
(&&)
ne peut pas avoir des effets secondaires, donc il y a seulement deux raisons pour lesquelles vous voulez prendre soin six && y
est stricte dansy
:y
prend beaucoup de temps à calculer.y
peut être bas.a &=& b = (a && b) `unamb` (b && a)
(&&)
peut avoir des effets secondaires s'ils utilisentunsafePerformIO
, mais ensuite, vous obtenez ce que vous demandez!Data.Unamb.pand
fonction est définie comme exactement que (modulo quelques couches d'abstraction).Pas tout à fait. Haskell est pur (sauf pour
unsafePerformIO
et la mise en œuvre deIO
), et il n'y a aucun moyen de observer l'opération qui sera exécuté en premier (sauf pourunsafePerformIO
et la mise en œuvre deIO
). L'ordre d'exécution tout simplement n'a pas d'importance pour le résultat.&&
a un 9-valeur table de vérité, y compris le cas où un ou les deux arguments sontundefined
, et il définit l'opération exactement:Aussi longtemps que la mise en œuvre suit cette table, il est autorisé à exécuter les choses dans n'importe quel ordre qu'il veut.
(Si vous étudiez le tableau, vous remarquerez qu'il n'y a aucun moyen pour un séquentielle mise en œuvre de la suivre à moins qu'il exécute
a
d'abord, puisb
iffa
est Vrai. Mais Haskell implémentations ne sont pas tenus d'être séquentielle! Une mise en œuvre est toujours permis à coup de pied de l'exécution deb
chaque fois qu'il le veut; votre seule garantie est que, d'après le tableau, le résultat de l'exécution deb
ne peut que l'impact de votre programme lorsquea
est Vrai.)(Note que " la paresse est le seul moyen d'écrire un fonction avec une table de vérité comme ci-dessus; dans un langage comme C ou ML, tous les cinq, les lignes avec
undefined
en soit, l'argument serait force deundefined
comme le résultat, où en Haskell (et en C, car&&
est intégré dans le langage C) l'une des lignes peut avoirFalse
que le résultat à la place.)Je crois qu'il fonctionne de la façon dont vous vous attendez; évaluer les RHS ssi le membre de GAUCHE est évaluée à True. Cependant, en supposant que le membre de droite n'a pas d'effets secondaires, comment voulez-vous savoir (ou de soins)?
Edit: je suppose que le membre de droite peut être
undefined
, et puis, soins...Prelude
qui sert comme une spécification. Et il est parfaitement bien de faire attention à ce, depuis(&&)
peut être utilisé pour combiner un simple & test rapide avec celle qui exige le plus de calcul.