Il est difficile d'ajouter quoi que ce soit aux explications d'Andrej ou de Neel, mais je vais essayer. Je vais essayer d'aborder le point de vue syntaxique, plutôt que de découvrir la sémantique sous-jacente, parce que l'explication est plus élémentaire et que je donnerai une réponse plus simple à votre question.
λ
La référence cruciale est la suivante:
Mendler, N. (1991). Types inductifs et contraintes de type dans le calcul lambda du second ordre. Je n'ai pas trouvé de référence en ligne, je le crains. Les déclarations et les preuves peuvent cependant être trouvées dans la thèse de doctorat de Nax (une lecture fortement recommandée!).
B a d
B a d = B a d →A
UNE
λ x : B a d . x x : B a d → A
et donc
( λ x : B a d . x x ) ( λ x : B a d . x x ) : A
B a d =F( B a d )
F( X)XF( X)
Bien sûr, vous ne travaillez pas avec des types définis équativement mais avec des constructeurs , c'est-à-dire que vous avez
data Bad = Pack (Bad -> A)
plutôt qu'une stricte égalité. Cependant, vous pouvez définir
unpack :: Bad -> (Bad -> A)
unpack (Pack f) = f
ce qui est suffisant pour que ce résultat continue de tenir:
(\x:Bad -> unpack x x) (Pack (\x:Bad -> unpack x x))
UNE
Dans votre deuxième exemple, les choses sont un peu plus délicates, car vous avez quelque chose comme
B a d = B a d′→ A
B a d′B a dB a d a B a d ( N o t a)
type Not a = a -> False
avec
data Not a = Not a
Il serait facilement résolu si Haskell permettait de telles définitions de type:
type Acc = Not Acc
Dans ce cas, vous pouvez créer un combinateur en boucle exactement de la même manière qu'auparavant. Je suppose que vous pouvez réaliser une construction similaire (mais plus complexe) en utilisant
data Acc = D (Not Acc)
Le problème ici est que pour construire un isomorphisme
Bad Acc <-> Bad (Not Acc)
vous devez faire face à une variance mixte.