Lemme: En supposant une équivalence éta, nous avons cela (\x -> ⊥) = ⊥ :: A -> B
.
Preuve: ⊥ = (\x -> ⊥ x)
par eta-équivalence, et (\x -> ⊥ x) = (\x -> ⊥)
par réduction sous lambda.
Le rapport Haskell 2010, section 6.2 spécifie la seq
fonction par deux équations:
seq :: a -> b -> b seq ⊥ b = ⊥ seq ab = b, si a ≠ ⊥
Il affirme ensuite "En conséquence, ⊥ n'est pas la même chose que \ x -> ⊥, car seq peut être utilisé pour les distinguer."
Ma question est la suivante: est-ce vraiment une conséquence de la définition de seq
?
L'argument implicite semble être que ce seq
ne serait pas calculable si seq (\x -> ⊥) b = ⊥
. Cependant, je n'ai pas été en mesure de prouver qu'un tel seq
serait impossible à calculer. Il me semble qu'un tel seq
est à la fois monotone et continu, ce qui le place dans le domaine du calculable.
Un algorithme qui implémente tel que seq pourrait fonctionner en essayant d'en chercher x
où f x ≠ ⊥
en énumérant le domaine de f
départ avec ⊥. Bien qu'une telle implémentation, même si possible, devienne assez velue une fois que nous voulons rendre seq
polymorphe.
Y a-t-il une preuve qu'il n'y a pas de calculable seq
qui s'identifie (\x -> ⊥)
à ⊥ :: A -> B
? Sinon, est - il une construction seq
qui n'identifie (\x -> ⊥)
avec ⊥ :: A -> B
?
la source
seq
de manière intelligente, ce qui implique la génération d'un nombre infini de processus, chacun appliquant votre fonction à un élément de base. Si l'un des processus se termine,seq
vous pouvez continuer. Il serait intéressant de voir si nous pouvons le faire séquentiellement. Hmm.Notez que la spécification pour
seq
laquelle vous citez est pas sa définition. Pour citer le rapport Haskell "La fonction seq est définie par les équations : [et ensuite les équations que vous donnez]".Un tel comportement violerait la spécification de
seq
.Surtout, puisque
seq
est polymorphe,seq
il ne peut pas être défini en termes de déconstructeurs (projections / correspondance de motifs, etc.) sur l'un ou l'autre des deux paramètres.Si
seq' (\x -> ⊥) b
, on pourrait penser que nous pourrions appliquer le premier paramètre (qui est une fonction) à une valeur, puis sortir ⊥. Mais,seq
ne peut jamais identifier le premier paramètre avec une valeur de fonction (même s'il se trouve que c'est un pour une certaine utilisation deseq
) en raison de son type polymorphe paramétrique. La paramétricité signifie que nous ne savons rien des paramètres. De plus,seq
ne peut jamais prendre une expression et décider "est-ce ⊥?" (cf. le problème de Halting),seq
ne peut que tenter de l'évaluer, et diverge lui-même vers ⊥.Ce qui
seq
fait est d'évaluer le premier paramètre (pas complètement, mais de "forme normale de tête faible" [1], c'est-à-dire au constructeur le plus haut), puis de retourner le deuxième paramètre. Si le premier paramètre se trouve être⊥
(c.-à-d. Un calcul sans terminaison), alors son évaluation entraîne laseq
non-terminaison, et ainsiseq ⊥ a = ⊥
.[1] Free Theorems in the Presence of seq - Johann, Voigtlander http://www.iai.uni-bonn.de/~jv/p76-voigtlaender.pdf
la source
f : forall a . a -> T
(où seT
trouve un autre type), alorsf
ne peut appliquer aucun déconstructeur à son premier argument car il ne sait pas quels déconstructeurs appliquer. Nous ne pouvons pas faire un "cas" sur les types. J'ai essayé d'améliorer la réponse ci-dessus (notamment en citant des informations sur l'seq
évaluation de la forme normale de la tête).Samson Abramsky a étudié ce problème il y a longtemps et a écrit un article intitulé " The Lazy Lambda Calculus ". Donc, si vous voulez des définitions formelles, c'est là que vous pourriez regarder.
la source
Prouver que λ x. Ω ≠ Ω in est l'un des objectifs qu'Abramsky se fixe pour sa théorie du calcul lambda paresseux (page 2 de son article , déjà cité par Uday Reddy), car ils sont tous deux sous une forme normale de tête faible. À partir de la définition 2.7, il discute explicitement que l'éta-réduction λ x. M x → M n'est généralement pas valide, mais cela est possible si M se termine dans tous les environnements. Cela ne signifie pas que M doit être une fonction totale - seulement que l'évaluation de M doit se terminer (en réduisant par exemple à un lambda).
Votre question semble être motivée par des préoccupations pratiques (performances). Cependant, même si le rapport Haskell est loin d’être tout à fait clair, je doute que l’égalisation de λ x. ⊥ avec ⊥ produirait une implémentation utile de Haskell; si elle implémente Haskell '98 ou non est discutable, mais étant donné la remarque, il est clair que les auteurs voulaient que ce soit le cas.
Enfin, comment seq pour générer des éléments pour un type d'entrée arbitraire? (Je sais que QuickCheck définit la classe de types arbitraire pour cela, mais vous n'êtes pas autorisé à ajouter de telles contraintes ici). Cela viole la paramétricité.
Mise à jour : je n'ai pas réussi à coder ce droit (parce que je ne parle pas aussi bien Haskel), et corriger cela semble nécessiter des
runST
régions imbriquées . J'ai essayé d'utiliser une seule cellule de référence (dans la monade ST) pour enregistrer ces éléments arbitraires, les lire plus tard et les rendre universellement disponibles. La paramétricité prouve quebreak_parametricity
ci - dessous ne peut pas être défini (sauf en retournant bottom, par exemple une erreur), alors qu'il pourrait récupérer les éléments que votre séquence proposée générerait.Je dois admettre que je suis un peu flou sur la formalisation de la preuve de paramétrie nécessaire ici, mais cette utilisation informelle de la paramétrie est standard dans Haskell; mais j'ai appris des écrits de Derek Dreyer que la théorie nécessaire s'est rapidement développée au cours de ces dernières années.
MODIFICATIONS:
la source
(\x -> writeSTRef cell (Just x) >> return x)
sur des entrées aléatoires n'exécute pas d'écriture dans la cellule. Seules les commandes ST qui entrent dans la séquence passéerunST
sont exécutées. De même, l'exécutionmain = (putStrLn "Hello") `seq` (return ())
n'imprime rien sur l'écran.