Ước mơ lập trình khai báo [đóng]


26

Tại sao giấc mơ lập trình khai báo không được thực hiện? Một số trở ngại cụ thể nhận được trên đường là gì? Cho một ví dụ đơn giản tại sao tôi không thể nói

sort(A) is defined by sort(A) in perm(A) && asc(sort(A))

và tự động lấy một thuật toán sắp xếp ra khỏi nó. permcó nghĩa là hoán vị và asccó nghĩa là tăng dần.


4
Nhân tiện, ví dụ cụ thể của bạn là loại đã có sẵn: gkoberger.github.io/stacksort
Den

3
Bạn đã nghe nói về Prolog? Chỉ cần tìm "Lập trình trả lời thiết lập". Có rất nhiều hệ thống được xây dựng dựa trên logic mặc định.
schlingel

16
Vâng, câu hỏi này dễ dàng được trả lời. Cố gắng thực hiện một hệ thống như vậy . Điều gì ngăn bạn làm điều đó thành công? Odds là tốt mà bất cứ điều gì bạn dừng lại đã dừng mọi người khác.
Eric Lippert

4
Tôi muốn tin rằng câu hỏi này xứng đáng nhận được nhiều tín dụng hơn nó nhận được. Khi bạn nhìn vào nó từ cái nhìn đầu tiên, bạn có thể nghĩ, Chà, thật đơn giản! Bạn phải lập trình tất cả logic đó đằng sau nó, và máy tính thì không thông minh đến thế. ... Nhưng sau đó bạn quay lại và lướt qua câu hỏi thứ hai và bạn nghĩ một lần nữa, À, vâng, điều đó thật đơn giản và bạn phải lập trình tất cả logic đó - và máy tính không nhất thiết phải là công cụ sắc bén nhất trong nhà kho, đúng - nhưng có nhiều chiều sâu cho lời giải thích đó hơn những gì chỉ đơn giản nằm ở bề mặt.
Panzercrisis

3
Mô tả của bạn về một thuật toán sắp xếp là khai báo, vâng, nhưng chắc chắn rằng địa ngục không hiệu quả. Có các n!hoán vị của một chuỗi và trong trường hợp xấu nhất, thuật toán của bạn sẽ phải thử tất cả chúng để tìm một thứ tự được sắp xếp. Thời gian yếu tố cũng tệ như một thuật toán để xử lý một chuỗi có thể làm.
Benjamin Hodgson

Câu trả lời:


8

Có một số câu trả lời rất tốt. Tôi sẽ cố gắng đóng góp cho cuộc thảo luận.

Về chủ đề khai báo, lập trình logic trong Prolog, có cuốn sách tuyệt vời "The Craft of Prolog" của Richard O'Keefe . Đó là về việc viết các chương trình hiệu quả bằng ngôn ngữ lập trình cho phép bạn viết các chương trình rất kém hiệu quả. Trong cuốn sách này, trong khi thảo luận về việc triển khai hiệu quả một số thuật toán (trong chương "Phương pháp lập trình"), tác giả đã thực hiện cách tiếp cận sau:

  • xác định vấn đề bằng tiếng Anh
  • viết một giải pháp làm việc càng khai báo càng tốt; thông thường, điều đó có nghĩa khá chính xác những gì bạn có trong câu hỏi của mình, chỉ cần sửa Prolog
  • từ đó, thực hiện các bước để tinh chỉnh việc thực hiện để làm cho nó nhanh hơn

Quan sát giác ngộ nhất (đối với tôi) tôi có thể thực hiện trong khi thực hiện theo cách này:

Có, phiên bản cuối cùng của việc triển khai hiệu quả hơn nhiều so với thông số kỹ thuật "khai báo" mà tác giả bắt đầu. Nó vẫn rất khai báo, cô đọng và dễ hiểu. Điều đã xảy ra ở giữa là giải pháp cuối cùng nắm bắt được các thuộc tính của vấn đề mà giải pháp ban đầu bị lãng quên.

Nói cách khác, trong khi thực hiện một giải pháp, chúng tôi đã sử dụng càng nhiều kiến ​​thức về vấn đề càng tốt. Đối chiếu:

Tìm một hoán vị của một danh sách sao cho tất cả các phần tử theo thứ tự tăng dần

đến:

Hợp nhất hai danh sách được sắp xếp sẽ dẫn đến một danh sách được sắp xếp. Vì có thể có các danh sách con đã được sắp xếp, hãy sử dụng chúng làm điểm bắt đầu, thay vì danh sách phụ có độ dài 1.

Một khía cạnh nhỏ: một định nghĩa giống như định nghĩa bạn đã đưa ra là hấp dẫn bởi vì nó rất chung chung. Tuy nhiên, tôi không thể thoát khỏi cảm giác rằng nó cố tình bỏ qua thực tế là hoán vị là một vấn đề tổ hợp. Đây là điều chúng ta đã biết ! Đây không phải là một lời chỉ trích, chỉ là một quan sát.

Như câu hỏi thực sự: làm thế nào để tiến về phía trước? Vâng, có một cách là cung cấp càng nhiều kiến ​​thức về vấn đề chúng ta đang tuyên bố với máy tính.

Nỗ lực tốt nhất mà tôi biết để thực sự giải quyết vấn đề được trình bày trong các cuốn sách do Alexander Stepanov đồng tác giả, "Các yếu tố lập trình""Từ toán học đến lập trình chung" . Đáng buồn là tôi không theo kịp nhiệm vụ tóm tắt (hoặc thậm chí hiểu đầy đủ) mọi thứ trong những cuốn sách này. Tuy nhiên, cách tiếp cận là xác định các thuật toán thư viện và cấu trúc dữ liệu hiệu quả (hoặc thậm chí tối ưu), theo quy định rằng tất cả các thuộc tính có liên quan của đầu vào đều được biết trước. Kết quả cuối cùng là:

  • Mỗi phép biến đổi được xác định rõ là một sự tinh chỉnh các ràng buộc đã có (các thuộc tính đã biết);
  • Chúng tôi để máy tính quyết định chuyển đổi nào là tối ưu dựa trên các ràng buộc hiện có.

Về lý do tại sao nó chưa xảy ra, khoa học máy tính là một lĩnh vực rất trẻ và chúng tôi vẫn đang đối phó với việc thực sự đánh giá cao sự mới lạ của hầu hết nó.

PS

Để cung cấp cho bạn một ý nghĩa của những gì tôi muốn nói bằng cách "tinh chỉnh việc thực hiện": ví dụ như vấn đề dễ dàng để có được yếu tố cuối cùng của danh sách, trong Prolog. Các giải pháp khai báo chính tắc là để nói:

last(List, Last) :-
    append(_, [Last], List).

Ở đây, ý nghĩa khai báo append/3là:

List1AndList2là sự kết hợp của List1List2

Vì trong đối số thứ hai append/3chúng ta có một danh sách chỉ có một phần tử và đối số thứ nhất bị bỏ qua (dấu gạch dưới), chúng ta có một phần của danh sách gốc loại bỏ phần trước của danh sách ( List1trong ngữ cảnh append/3) và yêu cầu mặt sau ( List2trong bối cảnh append/3) thực sự là một danh sách chỉ có một yếu tố: vì vậy, nó là yếu tố cuối cùng.

Các thực hiện thực tế được cung cấp bởi SWI-Prolog , tuy nhiên, nói:

last([X|Xs], Last) :-
    last_(Xs, X, Last).

last_([], Last, Last).
last_([X|Xs], _, Last) :-
    last_(Xs, X, Last).

Đây vẫn là tuyên bố độc đáo. Đọc từ trên xuống dưới, nó nói:

Phần tử cuối cùng của danh sách chỉ có ý nghĩa đối với danh sách ít nhất một phần tử. Phần tử cuối cùng cho một cặp đuôi và phần đầu của danh sách, sau đó là: phần đầu, khi phần đuôi trống hoặc phần cuối của phần đuôi không trống.

Lý do tại sao việc triển khai này được cung cấp là để giải quyết các vấn đề thực tế xung quanh mô hình thực thi của Prolog. Lý tưởng nhất, nó không nên tạo ra sự khác biệt mà việc thực hiện được sử dụng. Tương tự như vậy, chúng ta có thể nói:

last(List, Last) :-
    reverse(List, [Last|_]).

Phần tử cuối cùng của danh sách là phần tử đầu tiên của danh sách đảo ngược.

Nếu bạn muốn nhận được đầy đủ các cuộc thảo luận không có hồi kết về những gì tốt, Prolog khai báo, chỉ cần xem qua một số câu hỏi và câu trả lời trong thẻ Prolog trên Stack Overflow .


2
+1 để chỉ ra cách thiết kế khai báo có thể tiến triển từ sự trừu tượng hóa đơn giản đến việc triển khai cụ thể hơn thông qua quy trình thiết kế lặp.
itbruce 10/03/2015

1
@Boris Đây là một câu trả lời tốt. Cuốn sách đó đang ngồi trên kệ sách của tôi. Có lẽ đã đến lúc tôi mở nó ra.
davidk01

1
@ davidk01 Một trong những cuốn sách hay hơn ngoài kia. Nó giả định rằng bạn khá thoải mái với Prolog và lập trình nói chung, nhưng cách tiếp cận cần có để lập trình là cả thực dụng và rất kỹ lưỡng.
XXX

2
@Boris Tôi biết ví dụ này không phức tạp nhưng năng suất của quy trình thiết kế lặp - một thế mạnh thực sự của ngôn ngữ khai báo - và nó rất có giá trị thực tế, là rất quan trọng. Ngôn ngữ khai báo cung cấp một cách tiếp cận rõ ràng, nhất quán, đệ quy để cải thiện lặp đi lặp lại. Ngôn ngữ bắt buộc không.
itbruce 10/03/2015

1
+1 cho "nhận được đầy đủ các cuộc thảo luận không có hồi kết về những gì tốt, Prolog khai báo" rất đúng mà chúng tôi có xu hướng không đồng ý!
Daniel Lyons

50

Ngôn ngữ logic đã làm điều này. Bạn có thể định nghĩa sắp xếp tương tự như bạn đang làm điều đó.

Vấn đề chính là hiệu suất. Máy tính có thể rất giỏi trong việc tính toán rất nhiều thứ, nhưng chúng vốn đã bị câm. Mọi quyết định "thông minh" mà máy tính có thể đưa ra được lập trình viên đưa vào. Và quyết định này thường được mô tả không phải bằng cách kết quả cuối cùng trông như thế nào, mà bằng cách đạt được, từng bước, kết quả cuối cùng này.

Hãy tưởng tượng câu chuyện về một con Golem . Nếu bạn cố gắng đưa cho anh ta một mệnh lệnh trừu tượng, thì tốt nhất, anh ta sẽ làm điều đó không hiệu quả và tệ nhất, sẽ làm tổn thương chính anh ta, bạn hoặc người khác. Nhưng nếu bạn mô tả những gì bạn muốn một cách chi tiết nhất có thể, bạn được đảm bảo rằng nhiệm vụ sẽ được hoàn thành một cách hiệu quả và hiệu quả.

Công việc của lập trình viên là quyết định mức độ trừu tượng sẽ sử dụng. Đối với ứng dụng bạn đang thực hiện, bạn sẽ đi đến cấp độ cao và mô tả nó theo cách trừu tượng và đạt hiệu suất thấp hoặc bẩn, dành nhiều thời gian hơn cho nó, nhưng có được thuật toán hiệu suất cao hơn 1000 lần?


6
Có thể giúp biết rằng từ Golem ג TOUR לם thực sự có nghĩa là "nguyên liệu thô" tức là trạng thái cơ bản nhất mà máy / thực thể có thể ở đó.
dotancohen

2
Ngôn ngữ khai báo vốn không phải là một trở ngại cho mức độ trừu tượng thấp hơn. Theo cả hai cách khác nhau, Haskell và Standard ML cho phép bạn đưa ra các tuyên bố khai báo đơn giản về các loại / hàm ở một nơi, cung cấp một loạt các triển khai chức năng cụ thể và cụ thể ở một nơi riêng biệt và các cách để khớp các loại với các triển khai ở một nơi khác. Trong khi đó, thực tiễn tốt nhất trong các ngôn ngữ OO / mệnh lệnh bây giờ rất nhiều về việc bắt đầu cao / đơn giản và sau đó thêm chi tiết triển khai. Sự khác biệt là sự trừu tượng hóa cao dễ dàng hơn trong FP, mức độ thấp là dễ dàng hơn bắt buộc.
itbruce

2
Có thể nói rằng, trong cả hai ngôn ngữ được đề cập, cũng có thể tự động giải quyết việc lựa chọn triển khai cụ thể dựa trên các thuộc tính của loại thay vì khớp cụ thể mã hóa cứng, điều này mang lại khá nhiều điều OP muốn. Trong Haskell, các lớp loại sẽ là một công cụ chính cho việc này. Trong ML tiêu chuẩn, functor.
itbruce

22
@Ebar Golem! = Golum Golem là từ văn hóa dân gian Do Thái
Euphoric

10
Điểm nổi bật của tôi từ câu trả lời này là viết trên máy tính xách tay của tôi.
Dan J

45

Ngoài điểm tuyệt vời của Euphoric , tôi muốn nói thêm rằng chúng tôi đã sử dụng ngôn ngữ khai báo ở nhiều nơi chúng hoạt động tốt, tức là mô tả trạng thái không có khả năng thay đổi hoặc yêu cầu thứ gì đó mà máy tính thực sự có thể tạo mã hiệu quả tự nó

  • HTML tuyên bố nội dung của một trang web là gì.

  • CSS tuyên bố các loại yếu tố khác nhau trong một trang web sẽ trông như thế nào.

  • Mỗi cơ sở dữ liệu quan hệ có một ngôn ngữ định nghĩa dữ liệu khai báo cấu trúc của cơ sở dữ liệu là gì.

  • SQL gần với khai báo hơn là bắt buộc, vì bạn nói với nó những gì bạn muốn thấy và trình hoạch định truy vấn của cơ sở dữ liệu tìm ra cách thực sự làm cho nó xảy ra.

  • Người ta có thể lập luận rằng hầu hết các tệp cấu hình (.vimrc, .profile, .bashrc, .gitconfig) đang sử dụng ngôn ngữ dành riêng cho tên miền mà phần lớn là khai báo


3
Tôi sẽ đề cập đến GNU Make, XSLT, Angular.js như những thứ được sử dụng rộng rãi cũng là khai báo (mặc dù góc có thể đẩy định nghĩa lên một chút).
Mark K Cowan

Hãy để tôi thêm các biểu thức thông thường vào danh sách đó.
Schwern

7
Mọi người có xu hướng quên rằng ngôn ngữ khai báo là phổ biến . Họ thường không sử dụng ngôn ngữ hoàn chỉnh. Thêm regex vào danh sách đó.
slebetman

Một chút mô phạm, nhưng vẫn: Không phải mọi cơ sở dữ liệu đều có DDL, chỉ cần nghĩ về số lượng lớn cơ sở dữ liệu NoQuery. Mọi cơ sở dữ liệu quan hệ có thể có, nhưng không phải mọi cơ sở dữ liệu.
Phục hồi Monica - dirkk 10/03/2015

1
@dirkk Chưa nghĩ đến điều đó. Sửa câu trả lời của tôi.
Ixrec 10/03/2015

17

Trừu tượng bị rò rỉ

Bạn có thể thực hiện một hệ thống khai báo nơi bạn khai báo những gì bạn muốn và trình biên dịch hoặc trình thông dịch chỉ ra một thứ tự thực hiện. Lợi ích về mặt lý thuyết là nó giải phóng bạn khỏi phải suy nghĩ về 'làm thế nào' và bạn không phải chi tiết hóa việc thực hiện này. Tuy nhiên, trong thực tế cho tính toán cho mục đích chung, bạn vẫn phải suy nghĩ về 'cách thức' và viết tất cả các loại thủ thuật trong khi ghi nhớ cách thực hiện này, vì nếu không trình biên dịch có thể (và thường sẽ) chọn một triển khai sẽ rất, rất, rất chậm (ví dụ n! hoạt động trong đó n sẽ đủ).

Trong ví dụ cụ thể của bạn, bạn sẽ nhận được một thuật toán sắp xếp - điều đó không có nghĩa là bạn sẽ có được một thuật toán tốt hoặc thậm chí có thể sử dụng được. Định nghĩa đã cho của bạn, nếu được triển khai theo nghĩa đen (như một trình biên dịch có thể sẽ dẫn đến http://en.wikipedia.org/wiki/Bogosort , không thể sử dụng cho các bộ dữ liệu lớn hơn - nó đúng về mặt kỹ thuật, nhưng cần một số vĩnh viễn để sắp xếp hàng nghìn số .

Đối với một số miền hạn chế, bạn có thể viết các hệ thống hầu như luôn hoạt động tốt để tìm ra một triển khai tốt, ví dụ: SQL. Đối với điện toán cho mục đích chung không hoạt động đặc biệt tốt - bạn có thể viết các hệ thống, giả sử, Prolog nhưng bạn phải hình dung chính xác cách khai báo của bạn sẽ được chuyển đổi thành lệnh thực thi bắt buộc và cuối cùng sẽ mất phần lớn khai báo dự kiến lợi ích lập trình.


Mặc dù những gì bạn nói về cơ bản là đúng, nhưng hiệu suất kém không phải là dấu hiệu của sự trừu tượng bị rò rỉ trừ khi giao diện / hợp đồng cung cấp cho bạn sự đảm bảo, ví dụ về thời gian thực hiện.
valenterry

3
Peters không nói rằng hiệu suất kém là dấu hiệu của sự trừu tượng bị rò rỉ, @valenterry. Nếu bất cứ điều gì, ông đang nói ngược lại: rằng để đạt được hiệu suất tốt, chi tiết thực hiện buộc phải rò rỉ.
itbruce

2
Tôi nghĩ thật sai lầm khi nói rằng sự trừu tượng bị rò rỉ chỉ vì bạn cần hiểu việc thực hiện để hiểu nó ảnh hưởng đến hiệu suất như thế nào. Mục đích của một sự trừu tượng không phải là để bảo vệ bạn khỏi phải suy nghĩ về hiệu suất.
Doval

1
@jamesqf Trong lập trình khai báo, bạn sẽ chỉ nói rằng một cái gì đó được sắp xếp. Bạn có thể khai báo thứ tự sắp xếp được ràng buộc với một số biến / thuộc tính. Và sau đó nó sẽ là như vậy. Không cần phải gọi sắp xếp rõ ràng mỗi khi dữ liệu mới được thêm vào hoặc sắp xếp thay đổi thứ tự.
hyde

1
@jamesqf Bạn thực sự không thể nhìn thấy điểm mà không thực sự cố gắng (Tôi khuyên bạn nên QML của Qt để chơi với các ý tưởng khai báo). Hãy tưởng tượng ai đó chỉ biết lập trình bắt buộc và họ cố gắng hiểu điểm của OOP hoặc lập trình chức năng mà không thực sự thử nó.
hyde

11

Tính quyết định tính toán là lý do quan trọng nhất lập trình khai báo chưa được chứng minh là dễ dàng như nó có vẻ.

Nhiều vấn đề tương đối dễ nêu ra đã được chứng minh là không thể giải quyết được hoặc có độ phức tạp hoàn toàn NP để giải quyết. Điều này thường xảy ra khi chúng ta tính đến các lớp phủ định và phân loại, tính đếm và đệ quy.

Tôi muốn kiểm tra điều này với một số tên miền nổi tiếng.

Quyết định sử dụng lớp CSS nào cần có kiến ​​thức và xem xét tất cả các quy tắc CSS. Thêm quy tắc mới có thể làm mất hiệu lực tất cả các quyết định khác. Các lớp CSS phủ định không được thêm vào ngôn ngữ, vì các vấn đề hoàn thành NP, nhưng việc thiếu các lớp phủ định làm phức tạp các quyết định thiết kế CSS.

Trong trình tối ưu hóa truy vấn (SQL), có một vấn đề khó khăn khi quyết định nên tham gia vào thứ tự nào, chỉ số nào sẽ sử dụng và bộ nhớ nào sẽ phân bổ cho kết quả tạm thời nào. Đây là một vấn đề NP-đầy đủ đã biết và làm phức tạp việc thiết kế cơ sở dữ liệu và xây dựng truy vấn. Để hình thành nó một cách khác nhau: khi thiết kế cơ sở dữ liệu hoặc truy vấn, người thiết kế cần biết các hành động và thứ tự các hành động mà trình tối ưu hóa truy vấn có thể thực hiện. Một kỹ sư giàu kinh nghiệm cần kiến ​​thức về các heuristic được sử dụng bởi các nhà cung cấp cơ sở dữ liệu lớn.

Các tệp cấu hình là khai báo, nhưng các cấu hình nhất định khó khai báo. Ví dụ: để định cấu hình đúng các tính năng, người ta cần tính đến phiên bản tài khoản, triển khai (và lịch sử triển khai), có thể ghi đè thủ công và có thể xung đột với các cài đặt khác. Để xác thực hợp lệ một cấu hình có thể trở thành một vấn đề hoàn chỉnh NP.

Kết quả là những sự phức tạp này khiến người mới bắt đầu ngạc nhiên, chúng phá vỡ 'vẻ đẹp' của lập trình khai báo và chúng khiến một số kỹ sư tìm kiếm các giải pháp khác. Việc di chuyển các kỹ sư thiếu kinh nghiệm từ SQL sang NoQuery có thể đã được kích hoạt bởi sự phức tạp tiềm ẩn của cơ sở dữ liệu quan hệ.


2
"Các lớp CSS phủ định không được thêm vào ngôn ngữ, vì các vấn đề hoàn thành NP" - bạn có thể giải thích thêm không?
John Dvorak

Đó là một chút của một bài tập, nhưng với các bộ chọn CSS âm, có thể viết lại chúng thành vấn đề 3SAT (với mệnh đề cuối cùng là DOM), sẽ yêu cầu thử tất cả các kết hợp có thể, để xem nó có khớp không.
Dibbeke

1
Bổ sung nhỏ. Trong CSS 3 và 4, các bộ chọn phủ định được cho phép, nhưng: không phải các lớp giả có thể không được lồng nhau.
Dibbeke

2

Chúng tôi có một sự khác biệt về tính khử của các ngôn ngữ lập trình được sử dụng tốt trong việc xác minh logic kỹ thuật số.

Thông thường logic kỹ thuật số được mô tả ở mức truyền thanh ghi (RTL) trong đó mức logic của các tín hiệu giữa các thanh ghi được xác định. Để kiểm tra xem chúng ta đang ngày càng thêm các thuộc tính được định nghĩa theo cách trừu tượng và khai báo hơn.

Một trong những ngôn ngữ khai báo / tập hợp ngôn ngữ được gọi là PSL cho Ngôn ngữ Đặc tả Thuộc tính. Khi kiểm tra một mô hình RTL của một số nhân, trong đó, ví dụ, tất cả các hoạt động logic của sự thay đổi và thêm vào nhiều chu kỳ xung nhịp cần phải được chỉ định; bạn có thể viết một tài sản theo cách assert that when enable is high, this output will equal the multiplication of these two inputs after no more than 8 clock cycles. Mô tả PSL sau đó có thể được kiểm tra cùng với RTL trong một mô phỏng hoặc PSL có thể được chứng minh chính thức để giữ cho mô tả RTL.

Mô hình PSL khai báo nhiều hơn buộc người ta phải mô tả hành vi tương tự như mô tả RTL nhưng theo một cách đủ khác nhau có thể được kiểm tra tự động đối với RTL để xem họ có đồng ý hay không.


1

Chủ yếu là vấn đề là làm thế nào bạn mô hình hóa dữ liệu; và lập trình khai báo không giúp được gì ở đây. Trong các ngôn ngữ bắt buộc, bạn đã có hàng tấn thư viện cung cấp rất nhiều thứ cho bạn, vì vậy bạn chỉ cần biết phải gọi gì. Theo một cách cụ thể, người ta có thể xem xét lập trình khai báo này (có lẽ là ví dụ tốt nhất cho điều này là Stream API trong Java 8 ). Có điều này, sự trừu tượng đã được giải quyết và lập trình khai báo là không cần thiết.

Ngoài ra, như đã nói, các ngôn ngữ lập trình logic đã làm chính xác những gì bạn muốn. Người ta có thể nói vấn đề là hiệu suất, nhưng với phần cứng và nghiên cứu ngày nay trong lĩnh vực này, mọi thứ có thể được cải thiện để sẵn sàng cho việc sử dụng sản xuất; Thật ra Prolog được sử dụng cho công cụ AI, nhưng tôi chỉ tin vào giới hàn lâm.

Cần lưu ý rằng nó áp dụng cho các ngôn ngữ lập trình có mục đích chung. Đối với các ngôn ngữ cụ thể của miền, ngôn ngữ khai báo là cách tốt hơn; SQL có lẽ là ví dụ tốt nhất.


3
Mô hình hóa dữ liệu? Bạn đã chọn điều bắt buộc là tồi tệ nhất. Các ngôn ngữ chức năng khai báo như Haskell và ML excel ở mô hình dữ liệu. Các loại dữ liệu đại số và các loại dữ liệu đệ quy, ví dụ, thường có thể được định nghĩa toàn diện trong một hoặc hai dòng. Chắc chắn, bạn vẫn có các hàm để viết nhưng mã của chúng tuân theo một cách không thể hiểu được từ định nghĩa kiểu và bị ràng buộc bởi nó. So sánh kỳ quái để thực hiện.
itbruce

1
@itsbruce Điều đáng nói nhất là dữ liệu thực không dễ dàng được ánh xạ tới ADT; nghĩ về cách thức hoạt động của hầu hết các cơ sở dữ liệu Như Prolog - Erlang, bạn đã đúng, chúng là những ngôn ngữ khác nhau. Tôi đã đề cập rằng một là chức năng trong khi một cái khác là hợp lý nhưng là tốt nhất nếu tôi xóa toàn bộ so sánh.
m3th0dman

1
@ m3th0dman Một cơ sở dữ liệu chỉ là một tấn bộ / hồ sơ. Haskell hơi bị tê liệt ở đó, vì nó thiếu hồ sơ, nhưng nó có bộ dữ liệu và ML có cả hai. Và trong trường hợp của Haskell, số lượng bản ghi cần thiết để khai báo một kiểu dữ liệu bản ghi giả mới vẫn nhỏ hơn nhiều so với mức cần thiết để tạo một cấu trúc giả trong ngôn ngữ OOP được gõ tĩnh trung bình. Bạn có thể giải thích về cách hầu hết dữ liệu không dễ dàng được ánh xạ tới các ADT không?
Doval

1
@ m3th0dman Ah, đó là lý do tại sao các lược đồ cơ sở dữ liệu được xác định theo ngôn ngữ bắt buộc rất phù hợp với nhiệm vụ. Ồ, không, đó là DDL khai báo. Trong thực tế, toàn bộ quá trình mô hình hóa dữ liệu có liên quan đến ứng dụng sẽ làm việc với nó, các luồng dữ liệu và cấu trúc, chứ không phải ngôn ngữ thực hiện ứng dụng. Đôi khi những thứ đó bị biến dạng để phù hợp với các tính năng OO của ngôn ngữ và những gì ORM của nó hỗ trợ nhưng đó thường là một điều xấu, không phải là một tính năng. Ngôn ngữ khai báo phù hợp hơn để thể hiện mô hình dữ liệu khái niệm / logic.
itbruce

1
@itsbruce Tôi không nói rằng mô hình thủ tục tốt hơn mô hình khai báo khi xác định dữ liệu; Tôi đã nói rằng mô hình khai báo không tốt hơn (cũng không tệ hơn) so với mô hình thủ tục (đối với các ngôn ngữ có mục đích chung). Đối với việc thao túng dữ liệu, phần khai báo của SQL không đủ cho các ứng dụng thực tế; nếu không thì sẽ không ai phát minh và sử dụng các phần mở rộng thủ tục. Đối với bài viết, tôi không đồng ý với nó từ bản tóm tắt nơi nó mâu thuẫn với Brooks; ông đã xây dựng ý tưởng của mình từ các dự án thực tế trong khi những người đó không xây dựng bất cứ điều gì nổi bật để chứng minh lý thuyết của họ.
m3th0dman

0

Nó sẽ trông giống như thế này .. {(bất cứ điều gì => đọc một tệp và gọi một url) | gọi một url và đọc một tệp} Tuy nhiên, đây là những hành động để thực thi và trạng thái của hệ thống thay đổi do kết quả, nhưng điều đó không rõ ràng từ nguồn.

Tuyên bố có thể mô tả một máy trạng thái hữu hạn và quá trình chuyển đổi của nó. FSM giống như đối nghịch với các tuyên bố không có hành động, ngay cả khi hành động duy nhất là thay đổi trạng thái sang trạng thái tiếp theo.

Ưu điểm của việc sử dụng phương thức này là các hiệu ứng chuyển tiếp và hành động có thể được chỉ định bởi các vị từ áp dụng cho nhiều chuyển đổi, thay vì chỉ một.

Tôi biết điều này nghe có vẻ hơi lạ, nhưng vào năm 2008 tôi đã viết một trình tạo chương trình sử dụng phương thức này và C ++ được tạo ra gấp từ 2 đến 15 lần so với nguồn. Bây giờ tôi có hơn 75.000 dòng C ++ từ 20.000 dòng đầu vào. Hai điều đi với điều này: tính nhất quán và đầy đủ.

Tính nhất quán: Không có hai vị từ có thể đúng cùng một lúc có thể ngụ ý các hành động không nhất quán, vì cả x = 8 và x = 9, cũng không khác nhau về các trạng thái tiếp theo.

Tính đầy đủ: Logic cho mọi chuyển đổi trạng thái được chỉ định. Chúng có thể khó kiểm tra các hệ thống có N trạm, với các trạng thái> 2 ** N, nhưng có các phương pháp tổ hợp thú vị có thể xác minh mọi thứ. Vào năm 1962, tôi đã viết giai đoạn 1 của một loại hệ thống cho 7070 máy, sử dụng loại tạo mã có điều kiện và gỡ lỗi tổ hợp này. Trong số 8.000 dòng trong số đó, số lượng lỗi từ ngày phát hành đầu tiên mãi mãi là con số không!

Giai đoạn hai của loại, 12.000 dòng, đã có hơn 60 lỗi trong hai tháng đầu tiên. Có nhiều hơn để nói về điều này, nhưng nó hoạt động. Nếu các nhà sản xuất ô tô sử dụng phương pháp này để kiểm tra phần sụn, chúng ta sẽ không thấy những lỗi mà chúng ta thấy bây giờ.


1
Điều này thực sự không trả lời câu hỏi ban đầu. Làm thế nào để tính nhất quán và tính đầy đủ vào thực tế là hầu hết các chương trình vẫn là thủ tục, không phải là khai báo?
Jay Elston

Đoạn mở đầu của bạn dường như là một câu trả lời cho một điểm trong câu trả lời của lập trình viên arnaud.stackexchange.com/a/275839/67057 , không phải cho câu hỏi. Nó nên là một bình luận ở đó (trên màn hình của tôi, câu trả lời của bạn không còn dưới mức của anh ấy, vì một điều). Tôi nghĩ phần còn lại của câu trả lời của bạn là một minh họa về cách một lượng nhỏ mã khai báo có thể tạo ra một lượng lớn mã mệnh lệnh tương đương nhưng không rõ ràng. Câu trả lời của bạn cần được dọn dẹp, đặc biệt là liên quan đến các điểm nổi bật.
itbruce 11/03/2015

-3

Không phải tất cả mọi thứ có thể được đại diện theo một cách khai báo.

Thông thường, bạn rõ ràng muốn kiểm soát luồng thực thi

Ví dụ sau mã giả: if whatever read a file call an URL else call an URL write a file Làm thế nào bạn đại diện cho nó khai báo?

Chắc chắn, có lẽ có một số cách kỳ lạ để làm điều đó. Giống như monads . Nhưng những thứ này thường cồng kềnh, phức tạp và ít trực quan hơn nhiều so với phần thủ tục của chúng.

Tất cả tập trung vào thực tế là "tương tác" với môi trường / hệ thống của bạn không phải là khai báo. Tất cả mọi thứ liên quan đến I / O đều mang tính thủ tục. Bạn phải nói chính xác khi nào và điều gì sẽ xảy ra, và theo thứ tự nào.

Tuyên bố là tuyệt vời cho tất cả mọi thứ hoàn toàn liên quan đến tính toán. Giống như một hàm khổng lồ, bạn đặt X vào và bạn nhận được Y. Thật tuyệt vời. Một ví dụ cho điều này là HTML, đầu vào là văn bản, đầu ra là những gì bạn thấy trong trình duyệt của mình.


2
Tôi không mua cái này. Tại sao ví dụ của bạn không khai báo? Đây có phải là if/ else, trong trường hợp một thay thế khai báo sẽ trông như thế nào không? Đó chắc chắn không phải là read/ write/ callbộ phận, vì chúng là danh sách giá trị khai báo đẹp (nếu bạn ngụ ý chúng được bao bọc {...; ...}, tại sao không ngụ ý chúng được bọc trong [..., ...]?) Tất nhiên, danh sách chỉ là các đơn sắc miễn phí; nhiều người khác cũng sẽ làm như vậy. Tôi không thấy lý do tại sao các đơn vị có liên quan ở đây; chúng chỉ là một API. Haskell đã đi từ các luồng -> các đơn vị để hỗ trợ sáng tác thủ công, nhưng các ngôn ngữ logic có thể tự động soạn các danh sách theo thứ tự.
Warbo 10/03/2015

2
-1 cho Monads một mình. 1. Chúng không thực sự kỳ lạ (danh sách và bộ là Monads và mọi người đều sử dụng chúng). 2. Họ không có gì để làm với việc buộc mọi thứ phải được thực hiện theo một trình tự cụ thể ( ký hiệu Haskell vẻ bắt buộc nhưng không phải). Ngôn ngữ khai báo / chức năng xác định mối quan hệ và phụ thuộc. Nếu hàm X cần đầu vào Y, Y sẽ được tạo trước X. Nhận đúng các phụ thuộc và chuỗi sự kiện thích hợp sẽ tự xác định. Nhiều tương tác được điều khiển theo sự kiện , không theo một chuỗi tập hợp. Ngôn ngữ khai báo không làm cho việc phản ứng với các sự kiện khó khăn hơn.
itbruce 10/03/2015

Sự lười biếng làm phức tạp một số điều đó nhưng sự lười biếng không phải là một phần của định nghĩa của các ngôn ngữ Tuyên bố, hầu hết trong số đó không sử dụng nó. Và trong những điều đó, cách để đảm bảo đánh giá không liên quan gì đến các đơn nguyên. Đối với một ví dụ về việc ngôn ngữ khai báo được sử dụng riêng cho tương tác thay vì tính toán trừu tượng, không chỉ định thứ tự nhưng đảm bảo chắc chắn những điều đúng xảy ra theo trình tự, không khác gì so với DSL rối. Có phần thưởng mà chỉ những điều cần thiết xảy ra - không phải thứ gì đó bắt buộc phải làm cho ngôn ngữ trở nên dễ dàng.
itbruce 10/03/2015

1
Ngoài @itsbruce ví dụ lập trình phản ứng được xem xét khai báo và là về tương tác với môi trường.
Maciej Piechotka 10/03/2015
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.