È difficile aggiungere qualcosa alle spiegazioni di Andrej o Neel, ma ci proverò. Proverò ad affrontare il punto di vista sintattico, piuttosto che cercare di scoprire la semantica sottostante, perché la spiegazione è più elementare e posso dare una risposta più semplice alla tua domanda.
λ
Il riferimento cruciale è il seguente:
Mendler, N. (1991). Tipi induttivi e vincoli di tipo nel calcolo lambda del secondo ordine. Non ho trovato un riferimento online, temo. Le dichiarazioni e le prove possono tuttavia essere trovate nella tesi di dottorato di Nax (una lettura altamente raccomandata!).
B a d
B a d = B a d → A
UN
λ x : B a d . x x : B a d → A
e così
( λ x : B a d . x x ) ( λ x : B a d . x x ) : A
B a d =F( B a d )
F( X)XF( X)
Ovviamente stai lavorando non con tipi definiti equazionalmente ma con costruttori , cioè hai
data Bad = Pack (Bad -> A)
piuttosto che una rigorosa uguaglianza. Comunque puoi definire
unpack :: Bad -> (Bad -> A)
unpack (Pack f) = f
che è sufficiente affinché questo risultato continui a contenere:
(\x:Bad -> unpack x x) (Pack (\x:Bad -> unpack x x))
UN
Nel tuo secondo esempio, le cose sono un po 'più complicate, dato che hai qualcosa sulla falsariga di
B a d = B a d'→ A
B a d'B a dB a d a B a D ( N o t un)
type Not a = a -> False
con
data Not a = Not a
Sarebbe facilmente risolvibile se Haskell consentisse tali definizioni di tipo:
type Acc = Not Acc
In questo caso, è possibile creare un combinatore di loop esattamente come prima. Ho il sospetto che tu possa trasportare una costruzione simile (ma più complessa) usando
data Acc = D (Not Acc)
Il problema qui è quello di costruire un isomorfismo
Bad Acc <-> Bad (Not Acc)
devi affrontare una varianza mista.