Есть ли способ реализовать функцию типа ((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.
Амаллой
1
У @amalloy есть еще одна возможная реализация:g = const someHardcodedB
Федор Сойкин,
Ах, конечно. Это или aили b. Имеет смысл.
Амаллой
1
Если бы у Haskell был вызов / 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

но опять же мы вообще не можем.

phadej
источник
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. Просто недостаточно информации, когда типы универсально определены количественно.

Что касается того, почему изоморфизм не работает в Хаскеле - вы уверены, что эти предложения эквивалентны в конструктивной интуиционистской логике? Haskell не реализует классическую дедуктивную логику.

деревенщина
источник
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)
dfeuer
источник
0

Я понятия не имею, допустимо ли это с точки зрения логики или что это значит для вашей эквивалентности, но да, можно написать такую ​​функцию на Хаскеле.

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

to :: ((a -> b) -> b) -> Either a b
to f = let x = f (\_ -> x) in Right x
Берги
источник