Чи є спосіб реалізувати функцію типу ((a -> b) -> b) -> Або ab?


18

Пропозиції (P -> Q) -> Qі P \/ Qрівнозначні.

Чи є спосіб засвідчити цю еквівалентність у Haskell:

from :: Either a b -> ((a -> b) -> b)
from x = case x of
         Left a -> \f -> f a
         Right b -> \f -> b

to :: ((a -> b) -> b) -> Either a b
to = ???

такий як

from . to = idі to . from = id?


Мені здається очевидним, що це неможливо, але, можливо, я помиляюся. Якщо так, корисною відправною точкою є те, що функція із типово поліморфним типом ((a -> b) -> b)є ізоморфною для a: єдино можливою реалізацією є g f = f someHardcodedA.
amalloy

1
@amalloy є ще одна можлива реалізація:g = const someHardcodedB
Федір

Ах, звичайно. Це aабо b. Має сенс.
amalloy

1
Якби у Haskell був call / cc, тоді to f = callcc (\k -> k (Right (f (\a -> k (Left a)))))він працював би. (Це дійсне класичне підтвердження наслідків.)
benrg

Відповіді:


14

Пропозиції (P -> Q) -> Qі P \/ Qрівнозначні.

Це вірно в класичній логіці, але не в конструктивній логіці.

У конструктивній логіці у нас немає закону виключеного середини , тобто ми не можемо починати своє мислення з "або P є істинним, або P не відповідає дійсності".

Класично ми міркуємо так:

  • якщо P істинно (тобто у нас є ( x :: P)), тоді поверніться Left x.
  • якщо P неправдиво, тоді в Haskell говорять, ми мали б nx :: P -> Voidфункцію. Тоді absurd . nx :: P -> Q(ми можемо досягти максимум будь-якого типу, ми беремо Q) і будемо називати даними f :: (P -> Q) -> Q)з , absurd . nxщоб отримати значення типу Q.

Проблема в тому, що немає загальної функції типу:

lem :: forall p. Either p (p -> Void)

Для деяких типів бетону є, наприклад Bool, мешкають, щоб ми могли писати

lemBool :: Either Bool (Bool -> Void)
lemBool = Left True -- arbitrary choice

але знову ж таки, взагалі ми не можемо.


9

Ні, неможливо. Розглянемо окремий випадок, де Q = Void.

Either P Qце тоді Either P Void, що є ізоморфним P.

iso :: P -> Either P Void
iso = Left

iso_inv :: Either P Void -> P
iso_inv (Left p)  = p
iso_inv (Right q) = absurd q

Отже, якби у нас був термін функції

impossible :: ((P -> Void) -> Void) -> Either P Void

ми також могли б мати термін

impossible2 :: ((P -> Void) -> Void) -> P
impossible2 = iso_inv . impossible

Згідно листування Кері-Говарда, це буде тавтологією в інтуїтивістській логіці:

((P -> False) -> False) -> P

Але сказане вище - це подвійне усунення заперечення, що, як відомо, неможливо довести в інтуїтивістській логіці - отже, суперечність. (Те, що ми могли б довести це класичною логікою, не має значення.)

(Підсумкове зауваження: це передбачає, що програма Haskell припиняється. Звичайно, використовуючи нескінченну рекурсію, undefinedта подібні способи, щоб фактично уникнути повернення результату, ми можемо заселити будь-який тип в Haskell.)


4

Ні, це неможливо, але це трохи тонко. Проблема полягає в тому, що змінні типу aі bуніверсально визначаються кількісно.

to :: ((a -> b) -> b) -> Either a b
to f = ...

aі bє загальновизначеними. Абонент вибирає, який вони тип, тому ви не можете просто створити значення обох типів. Це означає, що ви не можете просто створити значення типу Either a b, ігноруючи аргумент f. Але використовувати fтакож неможливо. Не знаючи , які типи aі b, Ви не можете створити значення типу a -> bперейти на f. Існує недостатньо інформації, коли типи універсально оцінені.

Що стосується того, чому ізоморфізм не працює в Хаскеллі - ви впевнені, що ці пропозиції еквівалентні в конструктивній інтуїціоністській логіці? Хаскелл не реалізує класичну дедуктивну логіку.


2

Як зазначали інші, це неможливо, оскільки у нас немає закону виключеного середини. Дозвольте мені трохи детальніше пройти через це. Припустимо, у нас є

bogus :: ((a -> b) -> b) -> Either a b

і ми встановлюємо b ~ Void. Тоді ми отримуємо

-- chi calls this `impossible2`.
double_neg_elim :: ((a -> Void) -> Void) -> a
bouble_neg_elim f = case bogus f of
             Left a -> a
             Right v -> absurd v

Тепер докажемо подвійне заперечення закону виключеної середини , застосованого до конкретної пропозиції .

nnlem :: forall a. (Either a (a -> Void) -> Void) -> Void
nnlem f = not_not_a not_a
  where
    not_a :: a -> Void
    not_a = f . Left

    not_not_a :: (a -> Void) -> Void
    not_not_a = f . Right

Так що тепер

lem :: Either a (a -> Void)
lem = double_neg_elim nnlem

lemявно не може існувати, оскільки aможе кодувати положення про те, що будь-яка конфігурація машини Тьюрінга, яку я трапив, я зупиниться


Перевіримо, що lemдостатньо:

bogus :: forall a b. ((a -> b) -> b) -> Either a b
bogus f = case lem @a of
  Left a -> Left a
  Right na -> Right $ f (absurd . na)

0

Я поняття не маю, що це справедливо з точки зору логіки чи що це означає для вашої еквівалентності, але так, можна записати таку функцію в Haskell.

Щоб побудувати an Either a b, нам потрібно або значення, aабо bзначення. У нас немає способу побудувати aзначення, але у нас є функція, яка повертає значення, bяке ми могли б викликати. Для цього нам потрібно поставити функцію, яка перетворюється aв a b, але, враховуючи типи невідомі, ми могли б у кращому випадку зробити функцію, яка повертає константу b. Щоб отримати це bзначення, ми не можемо побудувати його будь-яким іншим способом, ніж раніше, тому це стає круговим міркуванням - і ми можемо вирішити це, просто створивши точну точку :

to :: ((a -> b) -> b) -> Either a b
to f = let x = f (\_ -> x) in Right x
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.