До пояснень Андрія чи Ніла важко додати що-небудь, але я спробую. Я спробую розглянути синтаксичну точку зору, а не намагатись розкрити основну семантику, тому що пояснення є більш елементарним, і я можу дати більш просту відповідь на ваше запитання.
Я буду працювати в просто набраному -calculus, а не в більш складній системі, що лежить в основі Haskell. Я вважаю, зокрема, що наявність змінних типів може певною мірою вас бентежити.λ
Найважливішим посиланням є наступне:
Мендлер, Н. (1991). Індуктивні типи та обмеження типу в обчисленні лямбда другого порядку. Боюсь, я не знайшов посилання в Інтернеті. Проте твердження та докази можна знайти в кандидатській дисертації Накса (настійно рекомендується читати!).
Мендлер пояснює, що позитивність є необхідною і достатньою умовою припинення за наявності нерекурсивних визначень випадків (і структурно зменшуваних рекурсивних). Він констатує це за допомогою рівняльної формулювання. Я наводжу простий приклад, який є спрощенням вашого типу .Bad
Bad=Bad→A
Де - будь-який тип. У нас тоді єA
λx:Bad.x x:Bad→A
і так
(λx:Bad.x x) (λx:Bad.x x):A
Мендлер показує, що це може бути здійснено для будь-якого типу
де - тип, що має принаймні одне негативне явище (можуть бути і позитивні випадки) . Він дає чіткий термін, який не може закінчитися для даного (стор. 39-40 його тези).F ( X ) X F ( X )
Bad=F(Bad)
F(X)XF(X)
Звичайно, ви працюєте не з рівнями, визначеними в рівній формі, а з конструкторами , тобто у вас є
data Bad = Pack (Bad -> A)
а не сувора рівність. Однак ви можете визначитись
unpack :: Bad -> (Bad -> A)
unpack (Pack f) = f
що достатньо для того, щоб цей результат і надалі мав місце:
(\x:Bad -> unpack x x) (Pack (\x:Bad -> unpack x x))
Цей термін ще типізований типу .A
У вашому другому прикладі все є дещо складніше, оскільки у вас є щось, що відбувається за принципом
Bad=Bad′→A
де є пов'язані , але НЕ рівні, до (в вашому випадку вони рівні і відповідно). Я визнаю, що я не міг побудувати прямого ізоморфізму між ними. Ця ж проблема є, якщо ви замінитеB a d B a d a B a d ( N o t a)Bad′BadBad aBad (Not a)
type Not a = a -> False
з
data Not a = Not a
Це було б легко вирішити, якби Haskell дозволив такі визначення типу:
type Acc = Not Acc
У цьому випадку ви можете створити циклічний комбінатор точно таким же чином, як і раніше. Я підозрюю, що ви можете виконати подібну (але більш складну) конструкцію, використовуючи
data Acc = D (Not Acc)
Біда в тому, що побудувати ізоморфізм
Bad Acc <-> Bad (Not Acc)
вам доведеться мати справу зі змішаною дисперсією.