Curry-Howard và các chương trình từ bằng chứng phi xây dựng


29

Đây là một câu hỏi tiếp theo để

Sự khác biệt giữa bằng chứng và chương trình (hoặc giữa các đề xuất và loại) là gì?

Chương trình nào sẽ tương ứng với một bằng chứng phi xây dựng (cổ điển) của mẫu ? (Giả sử rằng là một số mối quan hệ có thể quyết định thú vị, ví dụ: -th TM không dừng lại ở bước.)T e kk T(e,k)¬k T(e,k)Tek

(ps: Tôi đang đăng câu hỏi này một phần vì tôi muốn tìm hiểu thêm về ý nghĩa của Neel bởi " bản dịch Godel-Gentzen là một sự chuyển đổi tiếp tục" trong bình luận của anh ấy .)


2
Câu trả lời một phần trên trang 2 của các bài giảng này . Đó là một chút khó hiểu; Tôi sẽ cố gắng đào lên một cái gì đó hoàn thiện hơn.
Dave Clarke

Nó khiến tôi mất nhiều thời gian hơn dự định để viết câu trả lời của mình, vì tôi đã phạm sai lầm khi quyết định chứng minh những điều tôi biết thay vì chỉ khẳng định chúng. :)
Neel Krishnaswami

1
JSL gần đây nhất đã có bài viết này . Ý chính là nội dung tính toán của các bằng chứng cổ điển có thể phụ thuộc mạnh mẽ vào cách bạn chọn trích xuất nó. Tôi chưa thực sự tiêu hóa nó, nhưng tôi nghĩ tôi sẽ ném nó ra khỏi đó.
Đánh dấu Reitblatt

Nhưng bạn đã xác định rằng T là một mối quan hệ có thể quyết định , do đó, có nghĩa là có bằng chứng mang tính xây dựng về đề xuất của bạn. Logic cổ điển là một tập hợp con của logic trực giác và bạn đã xác định rằng T thuộc về tập hợp con đó bằng cách gọi nó là quyết định.
wren romano

wren, đó là những gì tôi nghĩ lúc đầu quá! Nhưng mệnh đề P trong ví dụ P \ / ~ P trong câu hỏi nếu thực sự định lượng trên tất cả k và định lượng T này không nhất thiết có thể quyết định được.
jbapple

Câu trả lời:


25

Đây là một câu hỏi thú vị. Rõ ràng người ta không thể mong đợi có một chương trình quyết định cho mỗi dù có giữ hay không, vì điều này sẽ quyết định vấn đề Dừng. Như đã đề cập, có một số cách giải thích bằng chứng tính toán: phần mở rộng của Curry-Howard, tính khả thi, phương ngữ, v.v. Nhưng tất cả họ sẽ giải thích tính toán định lý mà bạn đã đề cập ít nhiều theo cách sau.k T ( e , k )ekT(e,k)

Để đơn giản, hãy xem xét các định lý cổ điển tương đương

(1)ij(¬T(e,j)¬T(e,i))

Đây là (về mặt xây dựng) tương đương với cái được đề cập bởi vì quyết định liệu có giữ hay không bằng cách kiểm tra giá trị của . Nếu giữ thì và do đó . Mặt khác, nếu không giữ thì bởi (1) chúng ta có ngụ ý .k T ( e , k ) ¬ T ( e , i ) ¬ T ( e , i ) i ¬ T ( e , i ) ¬ i T ( e , i ) ¬ T ( e , i ) j ( ¬ T ( e , j ) )ikT(e,k)¬T(e,i)¬T(e,i)i¬T(e,i)¬iT(e,i)¬T(e,i)j(¬T(e,j))jT(e,j)

Bây giờ, một lần nữa, chúng ta không thể tính trong (1) cho mỗi cho bởi vì chúng ta sẽ lại giải quyết vấn đề Dừng. Điều mà tất cả các giải thích được đề cập ở trên sẽ làm là xem xét các định lý tương đươngeie

(2)fi(¬T(e,f(i))¬T(e,i))

Hàm được gọi là hàm Herbrand. Nó cố gắng tính toán một ví dụ phản cho mỗi nhân chứng tiềm năng đã cho . Rõ ràng là (1) và (2) là tương đương. Từ trái sang phải điều này mang tính xây dựng, chỉ cần đưa vào (2), trong đó là nhân chứng giả định của (1). Từ phải sang trái người ta phải suy luận kinh điển. Giả sử (1) là không đúng. Sau đó,j i i = i ifjii=ii

(3)ij¬(¬T(e,j)¬T(e,i))

Đặt là một hàm chứng kiến ​​điều này, tức làf

(4)i¬(¬T(e,f(i))¬T(e,i))

Bây giờ, lấy trong (2) và chúng ta có , đối với một số . Nhưng lấy trong (4), chúng ta có được sự phủ định của điều đó, mâu thuẫn. Do đó (2) ngụ ý (1). ( ¬ T ( e , f ' ( i ' ) ) ¬ T ( e , i ' ) ) i ' i = i 'f=f(¬T(e,f(i))¬T(e,i))ii=i

Vì vậy, chúng ta có (1) và (2) tương đương về mặt kinh điển. Nhưng điều thú vị là (2) giờ đây đã có một nhân chứng xây dựng rất đơn giản. Đơn giản chỉ cần lấy nếu không giữ, vì khi đó kết luận của (2) là đúng; hoặc nếu không, nếu giữ, vì sau đó không giữ và tiền đề của (2) là sai, làm cho nó trở lại đúng.T ( e , f ( 0 ) ) i = 0 T ( e , f ( 0 ) ) ¬ T ( e , f ( 0 ) )i=f(0)T(e,f(0))i=0T(e,f(0))¬T(e,f(0))

Do đó, cách để giải thích một cách tính toán một định lý cổ điển như (1) là xem xét một công thức tương đương (cổ điển) có thể được chứng minh một cách xây dựng, trong trường hợp của chúng tôi (2).

Các cách hiểu khác nhau được đề cập ở trên chỉ phân kỳ trên cách hàm bật lên. Trong trường hợp có thể thực hiện được và giải thích biện chứng, điều này được đưa ra một cách rõ ràng bằng cách giải thích, khi kết hợp với một số hình thức dịch tiêu cực (như của Goedel-Gentzen). Trong trường hợp tiện ích mở rộng Curry-Howard có toán tử gọi và tiếp tục, hàm phát sinh từ thực tế là chương trình được phép "biết" cách sử dụng một giá trị nhất định (trong trường hợp của chúng ), vì vậy là sự tiếp nối của chương trình xung quanh điểm mà được tính toán.f i f iffifi

Một điểm quan trọng khác là bạn muốn đoạn từ (1) đến (2) là "mô-đun", nghĩa là nếu (1) được sử dụng để chứng minh (1 '), thì nên sử dụng cách giải thích của nó (2) theo cách tương tự để chứng minh sự giải thích của (1 '), hãy nói (2'). Tất cả các giải thích được đề cập ở trên làm điều đó, bao gồm cả bản dịch phủ định Goedel-Gentzen.


8
Chào mừng bạn Thật tuyệt khi thấy một nhà lý thuyết bằng chứng chuyên gia ở đây.
Neel Krishnaswami

1
Cảm ơn Paulo, câu trả lời của bạn đã làm rõ một phần của bức tranh trong một vấn đề liên quan mà tôi đang làm việc.
Kaveh

17

Nó khá nổi tiếng rằng số học cổ điển và trực giác là tương đương.

Một cách để thể hiện điều này là thông qua "các nhúng âm" của logic cổ điển vào logic trực giác. Vì vậy, giả sử là công thức của số học bậc nhất cổ điển. Bây giờ, chúng ta có thể định nghĩa một công thức của logic trực giác như sau:ϕ

G()=¬¬G(ϕψ)=¬¬(G(ϕ)G(ψ))G()=¬G(¬ϕ)=¬G(ϕ)G(ϕψ)=¬(¬G(ϕ)¬G(ψ))G(x.ϕ)=x.¬¬G(ϕ)G(x.ϕ)=¬x.¬(G(ϕ))G(P)=¬¬P

Lưu ý rằng về cơ bản là một phép đồng hình dính vào không phải không phải ở khắp mọi nơi, ngoại trừ ở sự bất đồng và tồn tại, nó sử dụng tính đối ngẫu de Morgan để biến chúng thành liên từ và phổ quát. (Tôi khá tự tin rằng đây không phải là bản dịch chính xác của Godel-Gentzen, vì tôi đã nấu nó cho câu trả lời này - về cơ bản bất cứ điều gì bạn viết bằng cách sử dụng tính hai mặt + de Morgan sẽ hoạt động. Sự đa dạng này thực sự quan trọng đối với giải thích tính toán của logic cổ điển; xem bên dưới.)G(ϕ)

Thứ nhất: Rõ ràng là bản dịch này bảo tồn sự thật cổ điển, do đó là đúng khi và chỉ khi , nói một cách cổ điển.G(ϕ)ϕ

Thứ hai: Điều đó ít rõ ràng hơn, nhưng vẫn là trường hợp, đối với các công thức trong mảnh, khả năng chứng minh trong logic trực giác và cổ điển trùng khớp. Cách để chứng minh điều này là trước tiên hãy xem các công thức được rút ra từ ngữ pháp này:,,,¬

A,B::=x.A(x)|AB|AB|¬A|¬¬P

Và sau đó chúng ta có thể chứng minh như một bổ đề (bằng cách cảm ứng trên ) rằng là có thể dẫn xuất bằng trực giác. Vì vậy, bây giờ, chúng ta có thể chỉ ra tính công bằng của các công thức phủ định bằng cách thực hiện quy nạp trên cấu trúc của bằng chứng (tính toán, tính toán tuần tự) và sử dụng bổ đề trước để mô phỏng định luật loại trừ giữa.AG(A)A

Vì vậy, làm thế nào bạn nên suy nghĩ về điều này bằng trực giác?

  • Đầu tiên, quan điểm chứng minh lý thuyết. Nếu bạn nhìn vào các quy tắc của phép tính tuần tự, bạn có thể thấy rằng nơi duy nhất logic cổ điển và trực giác khác biệt nghiêm trọng là trong các quy tắc cho sự phân biệt và tồn tại. Vì vậy, chúng tôi đang sử dụng thực tế này để chỉ ra rằng các bằng chứng trong một logic của các công thức này có thể được dịch sang các bằng chứng khác. Điều này cho thấy cách nghĩ về logic xây dựng như một phần mở rộng của logic cổ điển với hai kết nối mới và . Cái mà chúng ta gọi là "sự tồn tại cổ điển" và "sự phân ly cổ điển" chỉ là những từ viết tắt liên quan đến , kết hợp và phủ định, và để nói về sự tồn tại thực tế, chúng ta cần phải giới thiệu các kết nối mới.

  • Thứ hai, có một quan điểm tô pô. Bây giờ, mô hình của logic cổ điển (như một họ các tập hợp) là một đại số Boolean (nghĩa là một họ các tập hợp con đóng dưới các hiệp nhất, giao điểm và bổ sung tùy ý). Nó chỉ ra rằng mô hình của logic trực giác là một không gian tôpô , với các mệnh đề được hiểu là các tập mở. Theo họ, việc giải thích phủ định là phần bên trong của phần bù, và sau đó thật dễ dàng để chỉ ra rằng , có nghĩa là phủ định kép sẽ đưa chúng ta vào clopen nhỏ nhất bao gồm mỗi lần mở --- và các clopens tạo thành một đại số Boolean.¬¬¬P=¬P

Bây giờ, nhờ có Curry-Howard, chúng tôi biết cách diễn giải các bằng chứng theo logic trực giác như các chương trình chức năng. Vì vậy, một câu trả lời có thể (nhưng không phải là duy nhất) cho câu hỏi "nội dung mang tính xây dựng của một bằng chứng cổ điển là gì?" như sau:

Nội dung tính toán của một bằng chứng cổ điển là bất cứ nội dung tính toán nào trong bản dịch chứng minh của nó (theo bản dịch phủ định).

Vì vậy, hãy xem bản dịch của . Vì vậy, điều này nói rằng nội dung mang tính xây dựng của phần giữa bị loại trừ cũng giống như nói rằng đó không phải là trường hợp và giữ - tức là không liên quan. Vì vậy, theo nghĩa này, thực sự không có nhiều nội dung tính toán theo luật trung gian bị loại trừ.G(A¬A)=¬(¬G(A)¬¬G(A))¬P¬¬P

Để xem cụ thể nó là gì, hãy nhớ lại một cách xây dựng, phủ định được định nghĩa là . Vì vậy, công thức này là . Các bit sau của mã Ocaml sẽ minh họa:( ( G ( A )¬A==A((G(A))((G(A))))

type bot = Void of bot
type 'a not = 'a -> bot

let excluded_middle : ('a not * 'a not not) not = fun (u, k) -> k u 

Đó là, nếu bạn nhận được không-A và không-không-A, bạn có thể chuyển từ phủ định đầu tiên sang thứ hai để rút ra mâu thuẫn bạn muốn.

Bây giờ, một biến đổi kiểu tiếp tục đi qua là gì?

  • Việc tiếp tục loại là một cái gì đó lấy giá trị của loại và tính toán câu trả lời cuối cùng từ nó.τττ
  • Tiếp tục được sử dụng để mô hình bối cảnh chương trình. Đó là chúng ta có thể có một thuật ngữ đánh giá là một phần của chương trình lớn hơn nhiều . Tất cả những thứ xung quanh nó sẽ lấy kết quả của tính toán và tính toán câu trả lời cuối cùng.C [ 3 + 5 ] 3 + 53+5C[3+5]3+5
  • Vì vậy, bạn có thể nghĩ về việc tiếp tục loại là một hàm , trong đó là bất cứ loại câu trả lời nào.τ α ατταα
  • Vì vậy, nếu bạn có một chương trình loại , chúng ta có thể "chuyển đổi CPS" bằng cách tìm một thuật ngữ loại , cuối cùng sẽ chuyển bất cứ thứ gì đã tính nó tiếp tục. (Về cơ bản, điều này chỉ làm cho dòng điều khiển rõ ràng.)τ ( τ α ) α eeτ(τα)αe
  • Nhưng chúng tôi phải thực hiện điều này một cách tự do, để mọi chương trình con của chương trình được thực hiện rõ ràng.

Hiện nay,

  • Về cơ bản, bản dịch phủ định sẽ gửi tới .¬ ¬ φϕ¬¬ϕ
  • Tuy nhiên, trong khi bản dịch của chúng tôi sử dụng phủ định, nó thực sự không bao giờ loại bỏ mệnh đề sai - vì vậy bản dịch hoạt động theo tham số trong mệnh đề đó.
  • Cụ thể, chúng tôi có thể thay thế bằng bất kỳ loại câu trả lời nào .alphaα
  • Vì vậy, chúng tôi đã thay thế bằng .( φ alpha ) alphaϕ(ϕα)α
  • Đây là một chuyển đổi CPS.

Tôi đã thấy "một" phép biến đổi CPS, vì như tôi đã đề cập trước đó, có nhiều bản dịch phủ định cho phép bạn chứng minh định lý này và mỗi bản dịch tương ứng với một thông số CPS khác nhau. Về mặt vận hành, mỗi phép biến đổi tương ứng với một thứ tự đánh giá khác nhau . Vì vậy, không có cách giải thích tính toán duy nhất nào cho logic cổ điển, vì bạn có lựa chọn để thực hiện và các lựa chọn khác biệt có các đặc điểm hoạt động rất khác nhau.


3
Đây là một câu trả lời tuyệt vời. Nó làm tôi nhớ đến bài báo của Wadler "Call-by-value là dual to call-by-name": homepages.inf.ed.ac.uk/wadler/topics/call-by-need.html , bao gồm một giai thoại rất đáng nhớ trong phần 4 để giải thích mối quan hệ giữa callCC và phần giữa bị loại trừ.
sclv

8

Có tất cả các hội nghị về chủ đề chứng minh phi xây dựng như các chương trình , và tôi không phải là chuyên gia về chủ đề này. Ở trên, Neel Krishnaswami đã ám chỉ một câu trả lời dài hơn mà anh ta đang chuẩn bị, mà, đánh giá từ công việc của anh ta ở đây, sẽ rất tuyệt vời. Đây chỉ là một hương vị của một câu trả lời.

Nó chỉ ra loại cuộc gọi tiếp tục hiện tại tương ứng với mệnh đề được gọi là luật Peirce , có thể được sử dụng để chứng minh Luật loại trừ trung gian ( ). Một chương trình LEM có thể được viết bằng callcc. Trong Coq:P,P¬P

Set Implicit Arguments.

Axiom callcc : forall (A B : Set), ((A -> B) -> A) -> A.

Lemma lem : forall (A B:Set), sum A (A -> B).
Proof.
  intros.
  eapply callcc.
  intros H.
  right.
  intros.
  apply H.
  left.
  assumption.
Defined.

Recursive Extraction lem.

cung cấp mã O'Caml:

type ('a, 'b) sum =
  | Inl of 'a
  | Inr of 'b

(** val callcc : (('a1 -> 'a2) -> 'a1) -> 'a1 **)

let callcc =
  failwith "AXIOM TO BE REALIZED"

(** val lem : ('a1, 'a1 -> no) sum **)

let lem =
    callcc (fun h -> Inr (fun h0 -> h (Inl h0)))

Giới thiệu rõ ràng nhất về điều này tôi đã thấy là trong "Khái niệm kiểm soát theo kiểu công thức" của Tim Griffin .


3
Bạn nên thử trích xuất vào Scheme và cho biết quy trình trích xuất sẽ trích xuất của bạn callccsang Scheme callcc. Sau đó, bạn thực sự có thể thử mọi thứ.
Andrej Bauer
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.