Bằng chứng là một chương trình; công thức mà nó chứng minh là một kiểu cho chương trình


37

Đây có thể là một loại câu hỏi triết học, nhưng tôi tin rằng có một câu trả lời khách quan cho nó.

Nếu bạn đọc bài viết trên wikipedia về Haskell, bạn có thể tìm thấy như sau:

Ngôn ngữ bắt nguồn từ những quan sát của Haskell Curry và con cháu trí thức của ông, rằng "một bằng chứng là một chương trình, công thức mà nó chứng minh là một loại cho chương trình"

Bây giờ, điều tôi đang hỏi là: điều này có thực sự áp dụng cho hầu hết các ngôn ngữ lập trình không? Tính năng nào (hoặc bộ tính năng) của Haskell làm cho nó phù hợp với tuyên bố này? Nói cách khác, những cách đáng chú ý trong đó tuyên bố này đã ảnh hưởng đến việc thiết kế ngôn ngữ là gì?


4
Bất cứ ai quan tâm để giải thích tại sao các phiếu "đóng", xin vui lòng?

1
@Grigory Javadyan: Tôi đã không bỏ phiếu để đóng, nhưng có lẽ vì câu hỏi không có chủ đề cho các câu hỏi triết học, có thể trả lời khách quan hay nói cách khác, nói chung không phù hợp ở đây. Tuy nhiên, trong trường hợp này tôi nghĩ nó hợp lý, bởi vì câu trả lời có ý nghĩa thực tiễn sâu sắc đối với cách Haskell thực sự được sử dụng.

2
@Grigory: nếu câu hỏi này là một vấn đề thực sự với một giải pháp thực sự (bằng mã) thì nó có thể ở lại SO. Bình chọn để đóng và di chuyển đến lập trình viên.

9
Chỉ để thêm vào điều đó bởi vì tôi hơi bị hấp dẫn - câu trả lời cho câu hỏi này đầy rẫy với các tài liệu tham khảo về nghiên cứu CS cứng và theo nghĩa đó "khách quan" hơn 90% SO. Hơn nữa, các tiêu chí của Sixlettervariable (rằng giải pháp cần mã) hoàn toàn hẹp đối với một loạt các câu hỏi lập trình chính hãng không mang tính chủ quan cũng không lạc đề. Tôi thực sự ghét phải xem cuộc tranh luận về chủ nghĩa hòa nhập / xóa bỏ trên SO, nhưng nếu các chủ đề lập trình rõ ràng như thế này bị
xáo trộn

2
Tôi không rõ về nơi mà điều này kết thúc, chủ yếu là vì tôi thực sự không rõ về loại nội dung nào được cho là dành cho Lập trình viên .E so với SO. Nhưng tôi sẽ nói rằng các lập trình viên được mô tả ở một số nơi là "câu hỏi chủ quan", mà câu hỏi này rõ ràng là không . Câu trả lời của tôi là về sự không chính thức và lượn sóng như có thể và tôi vẫn có thể sao lưu hầu hết dễ dàng với các tài liệu tham khảo ngay cả các biên tập viên Wikipedia nâng cao sẽ chấp nhận.
CA McCann

Câu trả lời:


38

Khái niệm thiết yếu áp dụng phổ biến trong một số thời trang, có, nhưng hiếm khi theo cách hữu ích.

Để bắt đầu, từ góc độ lý thuyết loại mà giả định này, các ngôn ngữ "động" được coi là có một loại duy nhất , chứa siêu dữ liệu (trong số những thứ khác) về bản chất của giá trị mà lập trình viên nhìn thấy, bao gồm cả những ngôn ngữ động này sẽ gọi là gì một "loại" bản thân (không giống nhau, về mặt khái niệm). Bất kỳ bằng chứng nào như vậy có khả năng không thú vị, vì vậy khái niệm này chủ yếu liên quan đến các ngôn ngữ có hệ thống kiểu tĩnh.

Ngoài ra, nhiều ngôn ngữ được cho là có "hệ thống loại tĩnh" phải được coi là động trong thực tế, trong bối cảnh này, vì chúng cho phép kiểm tra và chuyển đổi các loại tại thời điểm chạy. Cụ thể, điều này có nghĩa là bất kỳ ngôn ngữ nào được tích hợp, hỗ trợ theo mặc định cho "phản chiếu" hoặc tương tự. C #, ví dụ.

Haskell là không bình thường về số lượng thông tin mà nó mong đợi một loại sẽ cung cấp - đặc biệt, các hàm không thể phụ thuộc vào bất kỳ giá trị nào ngoài các giá trị được chỉ định làm đối số của nó. Trong một ngôn ngữ với các biến toàn cục có thể thay đổi, mặt khác, bất kỳ chức năng nào cũng có thể (có khả năng) kiểm tra các giá trị đó và thay đổi hành vi tương ứng. Vì vậy, một hàm Haskell với loại A -> Bcó thể được coi là một chương trình thu nhỏ chứng minh điều đó Angụ ý B; một chức năng tương đương trong nhiều ngôn ngữ khác sẽ chỉ cho chúng ta biết điều đó Avà bất kỳ trạng thái toàn cầu nào nằm trong phạm vi kết hợp ngụ ý B.

Lưu ý rằng mặc dù Haskell có hỗ trợ cho những thứ như kiểu phản xạ và kiểu động, việc sử dụng các tính năng đó phải được chỉ định trong chữ ký loại của hàm; tương tự như vậy để sử dụng nhà nước toàn cầu. Không có sẵn theo mặc định.

Cũng nhiều cách để phá vỡ mọi thứ trong Haskell, ví dụ như bằng cách cho phép ngoại lệ thời gian chạy hoặc sử dụng các hoạt động nguyên thủy không chuẩn do trình biên dịch cung cấp, nhưng chúng có một kỳ vọng mạnh mẽ rằng chúng sẽ chỉ được sử dụng với sự hiểu biết đầy đủ theo cách giành chiến thắng ' t làm hỏng ý nghĩa của mã bên ngoài. Về lý thuyết cũng có thể nói như vậy đối với các ngôn ngữ khác, nhưng trong thực tế với hầu hết các ngôn ngữ khác, việc hoàn thành mọi thứ sẽ khó khăn hơn nếu không "gian lận" và ít cau mày hơn khi "gian lận". Và tất nhiên trong các ngôn ngữ "động" thực sự, toàn bộ điều này vẫn không liên quan.

Khái niệm này có thể được đưa ra xa hơn nhiều so với trong Haskell.


Lưu ý rằng các ngoại lệ có thể được tích hợp hoàn toàn vào một hệ thống loại.
vườn

18

Bạn đã đúng rằng sự tương ứng của Curry-Howard là một điều rất chung chung. Thật đáng để làm quen với một chút về lịch sử của nó: http://en.wikipedia.org/wiki/Curry-Howard_corr phóng đại

Bạn sẽ lưu ý rằng theo công thức ban đầu, sự tương ứng này được áp dụng đặc biệt cho logic trực giác ở một bên và mặt khác là phép tính lambda (STLC) được gõ đơn giản.

Classic Haskell - phiên bản '98 hoặc thậm chí trước đó, đã rất chặt chẽ với STLC, và đối với hầu hết các phần, có một bản dịch trực tiếp rất đơn giản giữa bất kỳ biểu thức nào trong Haskell và một thuật ngữ tương ứng trong STLC (được mở rộng bằng đệ quy và một vài loại nguyên thủy). Vì vậy, điều này làm cho Curry-Howard rất rõ ràng. Ngày nay, nhờ các phần mở rộng, một bản dịch như vậy là một công việc khó khăn hơn.

Vì vậy, theo một nghĩa nào đó, câu hỏi là tại sao Haskell "desugars" vào STLC lại đơn giản như vậy. Hai điều tôi suy nghĩ:

  • Các loại. Không giống như Scheme, cũng là một phép tính lambda có đường (trong số những thứ khác), Haskell được đánh máy mạnh mẽ. Điều này có nghĩa là không tồn tại các thuật ngữ trong Haskell cổ điển mà theo định nghĩa không thể là các thuật ngữ được gõ tốt trong STLC.
  • Độ tinh khiết. Một lần nữa, không giống như Scheme, nhưng giống như STLC, Haskell là một ngôn ngữ thuần túy, minh bạch. Điều này khá quan trọng. Các ngôn ngữ có tác dụng phụ có thể được nhúng vào các ngôn ngữ không có tác dụng phụ. Tuy nhiên, làm như vậy là một sự chuyển đổi toàn bộ chương trình, không chỉ đơn giản là một sự hủy bỏ cục bộ. Vì vậy, để có sự tương ứng trực tiếp , bạn cần bắt đầu với một ngôn ngữ hoàn toàn chức năng.

Cũng có một cách quan trọng trong đó Haskell, giống như hầu hết các ngôn ngữ, thất bại liên quan đến việc áp dụng trực tiếp thư từ Curry-Howard. Haskell, như một ngôn ngữ hoàn chỉnh, chứa khả năng đệ quy không giới hạn, và do đó không chấm dứt. STLC không có toán tử fixpoint, không hoàn chỉnh và đang bình thường hóa mạnh mẽ - điều này có nghĩa là không giảm một thuật ngữ nào trong STLC sẽ không chấm dứt. Khả năng đệ quy có nghĩa là người ta có thể "lừa dối" Curry-Howard. Ví dụ, let x = x in xcó loạiforall a. a- tức là, vì nó không bao giờ trở lại, tôi có thể giả vờ nó mang lại cho tôi bất cứ thứ gì! Vì chúng ta luôn có thể làm điều này trong Haskell, điều đó có nghĩa là chúng ta không thể "tin" hoàn toàn vào bất kỳ bằng chứng nào tương ứng với chương trình Haskell trừ khi chúng ta có một bằng chứng riêng biệt rằng chính chương trình đó đang chấm dứt.

Dòng dõi lập trình chức năng trước Haskell (đáng chú ý là gia đình ML) là kết quả của nghiên cứu CS tập trung vào việc xây dựng ngôn ngữ mà bạn có thể dễ dàng chứng minh mọi thứ về (trong số những thứ khác), nghiên cứu rất nhiều về và bắt nguồn từ CH để bắt đầu. Ngược lại, Haskell vừa là ngôn ngữ chủ nhà vừa là nguồn cảm hứng cho một số trợ lý chứng minh đang được phát triển, như Agda và Epigram, bắt nguồn từ những phát triển trong lý thuyết loại rất liên quan đến dòng dõi CH.


1
Có thể là tốt để nhấn mạnh rằng sự hủy diệt làm suy yếu bằng chứng theo những cách nhất định, trong khi rõ ràng là thảm họa từ quan điểm logic, bảo tồn nhiều tính chất khác. Cụ thể, một hàm A -> B, được cung cấp A, sẽ tạo ra một Bhoặc không có gì cả. Nó sẽ không bao giờ tạo ra một C, và giá trị của loại Bmà nó cung cấp, hoặc nếu nó phân kỳ, vẫn phụ thuộc hoàn toàn vào Acung cấp.

@camccann - một chút nitpicky, nhưng tôi sẽ phân biệt giữa đáy và "không có gì cả", giống như là Voidkhông, phải không? Sự lười biếng làm cho nó ngày càng ít phức tạp hơn. Tôi muốn nói rằng một hàm A -> B luôn tạo ra một giá trị loại B, nhưng giá trị đó có thể có ít thông tin hơn người ta mong đợi.
sclv

Nitpicking là niềm vui! Khi tôi nói "không có gì", ý tôi là ở mức giá trị trong bối cảnh thực hiện đánh giá, trong khi đáy chỉ thực sự tồn tại như một sự trừu tượng, không phải là thứ gì đó hữu hình. Một biểu thức được đánh giá sẽ không bao giờ "nhìn thấy" một giá trị dưới cùng, chỉ các thuật ngữ mà nó không sử dụng (có thể là đáy) và các thuật ngữ mà nó sử dụng (có các giá trị không phải là đáy). Cố gắng sử dụng dưới cùng "không bao giờ xảy ra" trong một số ý nghĩa bởi vì cố gắng làm như vậy kết thúc việc đánh giá toàn bộ biểu thức trước khi sử dụng sẽ xảy ra.

12

Đối với một xấp xỉ bậc một, hầu hết các ngôn ngữ khác (yếu và / hoặc không gõ) không hỗ trợ phân định mức độ ngôn ngữ chặt chẽ giữa một

  • mệnh đề (tức là một loại)
  • một bằng chứng (tức là một chương trình chứng minh làm thế nào chúng ta có thể xây dựng đề xuất từ ​​một tập hợp các nguyên thủy và / hoặc các cấu trúc bậc cao khác )

và mối quan hệ chặt chẽ giữa hai. Nếu bất cứ điều gì, đảm bảo tốt nhất các ngôn ngữ khác cung cấp là

  • đưa ra một ràng buộc hạn chế về đầu vào, cùng với bất kỳ điều gì xảy ra trong môi trường tại thời điểm đó, chúng ta có thể tạo ra một giá trị với một ràng buộc hạn chế. (kiểu tĩnh truyền thống, cf C / Java)
  • mọi cấu trúc đều cùng loại ( kiểu động, cf ruby ​​/ python)

Lưu ý rằng theo loại , chúng tôi đề cập đến một đề xuất , và do đó một cái gì đó mô tả nhiều thông tin hơn sau đó chỉ đơn thuần là int hoặc bool . Trong Haskell, có một văn hóa thẩm thấu của một hàm chỉ bị ảnh hưởng bởi các đối số của nó - không có ngoại lệ *.

Để nghiêm khắc hơn một chút, ý tưởng chung là bằng cách thực thi một cách tiếp cận trực giác cứng nhắc đối với (gần) tất cả các cấu trúc chương trình (nghĩa là chúng ta chỉ có thể chứng minh rằng chúng ta có thể xây dựng) và bằng cách giới hạn tập hợp các cấu trúc nguyên thủy trong một cách mà chúng ta có

  • đề xuất nghiêm ngặt cho tất cả các nguyên thủy ngôn ngữ
  • một bộ cơ chế giới hạn mà theo đó các nguyên thủy có thể được kết hợp

Các công trình của Haskell có xu hướng cho vay rất tốt để lý luận về hành vi của họ. Nếu chúng ta có thể xây dựng một bằng chứng (đọc: hàm) chứng minh rằng Angụ ý B, thì đây là thuộc tính rất hữu ích:

  • luôn luôn giữ (miễn là chúng ta có A, chúng ta có thể xây dựng một B)
  • hàm ý này chỉ dựa vào A, và không có gì khác.

do đó cho phép chúng ta suy luận về bất biến địa phương / toàn cầu một cách hiệu quả. Để trở lại câu hỏi ban đầu; Các đặc điểm ngôn ngữ của Haskell làm mê hoặc suy nghĩ này nhất là:

  • Độ tinh khiết / Phân đoạn hiệu ứng thành các cấu trúc rõ ràng (các hiệu ứng đều được tính và được gõ!)
  • Nhập suy luận / Kiểm tra trong trình biên dịch Haskell
  • Khả năng nhúng điều khiển và / hoặc bất biến luồng dữ liệu vào các đề xuất / loại chương trình được đặt ra để chứng minh: (với Đa hình, Kiểu gia đình, GADT, v.v.)
  • Tính toàn vẹn tham chiếu

Không có cái nào trong số đó là duy nhất với Haskell (nhiều ý tưởng trong số này là vô cùng cũ). Tuy nhiên, khi được kết hợp cùng với một tập hợp trừu tượng phong phú trong các thư viện tiêu chuẩn (thường được tìm thấy trong các lớp loại), nhiều loại cấp độ cú pháp và cam kết chặt chẽ về độ tinh khiết trong thiết kế chương trình, chúng tôi kết thúc bằng một ngôn ngữ bằng cách nào đó quản lý được cả hai đủ thực tế cho các ứng dụng trong thế giới thực , nhưng đồng thời chứng minh dễ dàng hơn để lý luận về hầu hết các ngôn ngữ truyền thống.

Câu hỏi này xứng đáng với một câu trả lời đủ sâu sắc và tôi không thể thực hiện công lý trong bối cảnh này. Tôi khuyên bạn nên đọc thêm trên wikipedia / trong tài liệu:

* NB: Tôi đang che đậy / bỏ qua một số khía cạnh phức tạp hơn của tạp chất của Haskell (ngoại lệ, không chấm dứt, v.v.) sẽ chỉ làm phức tạp hóa đối số.


4

Tính năng gì? Hệ thống loại (là tĩnh, tinh khiết, đa hình). Một điểm khởi đầu tốt là "Định lý miễn phí" của Wadler. Hiệu quả đáng chú ý trên thiết kế của ngôn ngữ? Các loại IO, các lớp loại.


0

Các Kleene Hierarchy cho chúng ta thấy rằng bằng chứng không phải là chương trình.

Mối quan hệ đệ quy đầu tiên là:

R1( Program , Iteration )  Program halts at Iteration.
R2( Theorem , Proof ) Proof proves a Theorem.

Các mối quan hệ đệ quy đầu tiên là:

(exists x) R1( Program , x )  Program Halts.
(exists x) R2( Theorem , x)   Theorem is provable.

Vì vậy, một chương trình là một định lý và phép lặp tồn tại mà chương trình dừng lại giống như bằng chứng tồn tại chứng minh định lý.

Program = Theorem
Iteration = Proof

Khi một chương trình được sản xuất chính xác từ một đặc tả, chúng ta phải có khả năng chứng minh rằng nó thỏa mãn đặc tả đó và nếu chúng ta có thể chứng minh một chương trình thỏa mãn một đặc tả thì đó là tổng hợp chương trình chính xác. Vì vậy, chúng tôi thực hiện tổng hợp chương trình nếu chúng tôi chứng minh chương trình đáp ứng các đặc điểm kỹ thuật. Định lý mà chương trình thỏa mãn đặc tả là chương trình trong đó định lý đề cập đến chương trình được tổng hợp.

Kết luận sai lầm của Martin Lof chưa bao giờ tạo ra bất kỳ chương trình máy tính nào và thật đáng kinh ngạc khi mọi người tin rằng đó là một phương pháp tổng hợp chương trình. Không có ví dụ hoàn chỉnh nào được đưa ra về một chương trình đang được tổng hợp. Một đặc tả như "nhập một loại và xuất một chương trình của loại đó" không phải là một chức năng. Có nhiều chương trình như vậy và để chọn một chương trình ngẫu nhiên không phải là hàm đệ quy hoặc thậm chí là hàm. Nó chỉ là một nỗ lực ngớ ngẩn để hiển thị tổng hợp chương trình với một chương trình ngớ ngẩn không đại diện cho một chương trình máy tính thực sự tính toán một hàm đệ quy.


2
Làm thế nào để trả lời câu hỏi này, "những cách đáng chú ý trong đó tuyên bố này ảnh hưởng đến thiết kế của ngôn ngữ là gì?"
gnat

1
@gnat - câu trả lời này giải quyết một giả định cơ bản trong câu hỏi ban đầu, cụ thể là: " doesn't this really apply to pretty much all the programming languages?" Câu trả lời này tuyên bố / cho thấy giả định đó không hợp lệ, vì vậy không có ý nghĩa gì khi giải quyết phần còn lại của các câu hỏi dựa trên tiền đề thiếu sót .
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.