Có cách nào để nhận ra một hàm loại ((a -> b) -> b) -> Hoặc là ab?


18

Đề xuất (P -> Q) -> QP \/ Qlà tương đương.

Có cách nào để chứng kiến ​​sự tương đương này trong 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 = ???

như vậy mà

from . to = idto . from = id?


Nó có vẻ rõ ràng với tôi rằng điều này là không thể, nhưng có lẽ tôi đã sai. Nếu vậy, một điểm khởi đầu hữu ích là một hàm với kiểu đa hình hoàn toàn ((a -> b) -> b)là đẳng cấu với a: cách thực hiện duy nhất có thể là g f = f someHardcodedA.
amalloy

1
@amalloy có một triển khai khả thi khác:g = const someHardcodedB
Fyodor Soikin

À, tất nhiên rồi. Nó là một trong hai ahoặc b. Có ý nghĩa.
amalloy

1
Nếu Haskell có cuộc gọi / cc, thì to f = callcc (\k -> k (Right (f (\a -> k (Left a)))))sẽ hoạt động. (Đây là một bằng chứng cổ điển hợp lệ về hàm ý.)
benrg

Câu trả lời:


14

Đề xuất (P -> Q) -> QP \/ Qlà tương đương.

Điều này đúng trong logic cổ điển, nhưng không phải trong logic xây dựng.

Trong logic xây dựng, chúng ta không có luật trung gian bị loại trừ , tức là chúng ta không thể bắt đầu suy nghĩ của mình với "P là đúng hoặc P không đúng".

Cổ điển, chúng tôi lý do như:

  • nếu P đúng (tức là chúng ta có ( x :: P)) thì trả về Left x.
  • nếu P sai, thì trong Haskell, chúng ta sẽ có nx :: P -> Voidchức năng. Sau đó absurd . nx :: P -> Q(chúng ta có thể đạt đỉnh bất kỳ loại, chúng ta lấy Q) và gọi cho f :: (P -> Q) -> Q)absurd . nxđể có được giá trị của loại Q.

Vấn đề là không có chức năng chung của một loại:

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

Đối với một số loại bê tông có, ví dụ như Boolcó người ở để chúng ta có thể viết

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

nhưng một lần nữa, nói chung chúng ta không thể.


9

Không, nó là không thể. Hãy xem xét trường hợp đặc biệt trong đó Q = Void.

Either P Qlà sau đó Either P Void, đó là đẳng cấu 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

Do đó, nếu chúng ta có một thuật ngữ chức năng

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

chúng ta cũng có thể có một thuật ngữ

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

Theo sự tương ứng của Curry-Howard, đây sẽ là một tautology trong logic trực giác :

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

Nhưng ở trên là loại bỏ phủ định kép, được biết đến là không thể chứng minh bằng logic trực giác - do đó là một mâu thuẫn. (Thực tế là chúng ta có thể chứng minh điều đó trong logic cổ điển không liên quan.)

(Lưu ý cuối cùng: điều này giả định rằng chương trình Haskell chấm dứt. Tất nhiên, sử dụng đệ quy vô hạn undefinedvà các cách tương tự để thực sự tránh trả về kết quả, chúng ta có thể sống bất kỳ loại nào trong Haskell.)


4

Không, điều đó là không thể, nhưng nó hơi tinh tế. Vấn đề là các biến loại abđược định lượng toàn cầu.

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

abđược định lượng toàn cầu. Người gọi chọn loại của họ, vì vậy bạn không thể tạo giá trị của một trong hai loại. Điều này ngụ ý bạn không thể chỉ tạo một giá trị của loại Either a btrong khi bỏ qua đối số f. Nhưng sử dụng fcũng là không thể. Không biết loại nào ablà gì, bạn không thể tạo giá trị của loại a -> bđể chuyển đếnf . Không có đủ thông tin có sẵn khi các loại được định lượng toàn cầu.

Theo như lý do tại sao đẳng cấu không hoạt động trong Haskell - bạn có chắc những đề xuất đó là tương đương trong logic trực giác xây dựng? Haskell không thực hiện logic suy diễn cổ điển.


2

Như những người khác đã chỉ ra, điều này là không thể bởi vì chúng ta không có luật trung gian bị loại trừ. Hãy để tôi đi qua đó một chút rõ ràng hơn. Giả sử chúng ta có

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

và chúng tôi thiết lập b ~ Void. Sau đó, chúng tôi nhận được

-- 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

Bây giờ, hãy chứng minh sự phủ định kép của luật trung gian bị loại trừ khi áp dụng cho một đề xuất cụ thể .

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

Vậy bây giờ

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

lemrõ ràng không thể tồn tại bởi vì acó thể mã hóa đề xuất rằng bất kỳ cấu hình máy Turing nào tôi chọn sẽ dừng lại.


Hãy xác minh lemlà đủ:

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

Tôi không biết liệu điều này có hợp lệ về mặt logic hay ý nghĩa của sự tương đương của bạn hay không, nhưng vâng, có thể viết một hàm như vậy trong Haskell.

Để xây dựng một Either a b, chúng ta cần một ahoặc một bgiá trị. Chúng tôi không có cách nào để xây dựng một agiá trị, nhưng chúng tôi có một hàm trả về một giá trị bmà chúng tôi có thể gọi. Để làm điều đó, chúng ta cần cung cấp một hàm chuyển đổi athành một b, nhưng với các loại không xác định, tốt nhất chúng ta có thể tạo một hàm trả về một hằng số b. Để có được bgiá trị đó , chúng tôi không thể xây dựng nó theo bất kỳ cách nào khác trước đây, vì vậy điều này trở thành lý luận vòng tròn - và chúng tôi có thể giải quyết điều đó bằng cách chỉ cần tạo một điểm cố định :

to :: ((a -> b) -> b) -> Either a b
to f = let x = f (\_ -> x) in Right x
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.