- Prolog cấu thành chương trình bằng một mệnh đề (clause) duy nhất và mô hình dữ liệu xoay quanh term, nên có thể biểu diễn các quan hệ có thể tính toán được chỉ với một ngữ pháp nhỏ gọn
- Cách tiếp cận khai báo viết ra điều gì là đúng thay vì quy trình thực thi, nên cùng một quan hệ có thể dùng cho tính toán, sinh dữ liệu và truy vấn
- Prolog thuần túy dựa trên Horn clause và resolution, nên có thể dự đoán một cách logic ảnh hưởng của việc thêm ràng buộc và thêm mệnh đề lên tập nghiệm
- Bản thân chương trình cũng là một term của Prolog, nên dễ đọc, phân tích và biến đổi các chương trình khác; đồng thời có thể tạo ngôn ngữ đặc thù miền bằng cách tái viết ở thời điểm biên dịch
- Nhờ tính động ở runtime và các cơ chế ngầm như tìm kiếm, hợp nhất và lan truyền ràng buộc, Prolog được ứng dụng rộng rãi từ xử lý ngôn ngữ, cơ sở dữ liệu đến kiểm chứng và tối ưu hóa
Một ngôn ngữ nhỏ được tạo nên từ mệnh đề và term
- Mọi dữ liệu trong Prolog đều được biểu diễn bằng term của Prolog
- Thành phần cốt lõi của ngôn ngữ chỉ là một clause, với dạng cơ bản là
Head :- Body.
- Ý nghĩa là nếu Body đúng thì Head đúng
- Toán tử trung tố
(:-)/2 biểu thị mũi tên ← hướng từ phải sang trái
- Nếu Head luôn đúng thì có thể lược bỏ
:- Body
- Chỉ riêng cấu trúc này đã đủ để viết chương trình Prolog đầu tiên hữu ích
- Mọi phép tính đã biết đều có thể mô tả bằng các mệnh đề như vậy, nên Prolog là một ngôn ngữ Turing-complete
- Có thể hiện thực máy Turing bằng cách mô tả bằng mệnh đề quan hệ chuyển sang trạng thái kế tiếp từ trạng thái hiện tại và ký hiệu dưới đầu đọc băng, v.v.
- Có ví dụ triển khai tại turing.pl
Lập trình khai báo và tư duy hướng quan hệ
- Prolog là ngôn ngữ khai báo, diễn tả điều gì là đúng về các nghiệm cần quan tâm thay vì cách tìm nghiệm
- Đặc tính này cho phép tạo ra các đặc tả ngắn gọn, rõ ràng và tổng quát
- Quan hệ giữa danh sách và độ dài có thể được mô tả như sau
list_length([], 0).
list_length([_|Ls], N) :-
N #> 0,
N #= N0 + 1,
list_length(Ls, N0).
- Trong một số hệ Prolog, cần nạp thêm thư viện riêng để dùng số học số nguyên khai báo
- Định nghĩa này có thể được đọc theo cách khai báo như sau
- Danh sách rỗng
[] có độ dài là 0
- Nếu
Ls có độ dài N0 và N bằng N0 + 1 thì [_|Ls] có độ dài N, và quan hệ này chỉ đúng khi N lớn hơn 0
- Cùng một quan hệ có thể dùng ở nhiều chế độ
list_length("abc", L) trả về L = 3
list_length(Ls, 3) tìm một danh sách có độ dài 3 dưới dạng Ls = [_A,_B,_C]
list_length(Ls, L) liệt kê các đáp án tổng quát, từ danh sách rỗng đến các danh sách có độ dài tăng dần
- Prolog thường báo cáo mọi đáp án bằng backtracking
length/2 có trong bản thảo Prologue for Prolog và được cung cấp như một vị từ dựng sẵn với cùng ý nghĩa trong gần như mọi hiện thực Prolog
Prolog như một ngôn ngữ lập trình logic
- Trong nhóm ngôn ngữ khai báo có ngôn ngữ lập trình hàm và ngôn ngữ lập trình logic
- Hàm là trường hợp đặc biệt của quan hệ, nên có thể xem lập trình hàm là một dạng bị giới hạn của lập trình logic
- Prolog bắt nguồn từ logic
- Một chương trình Prolog thuần túy được cấu thành từ một tập các Horn clause
- Việc thực thi có thể được xem là một trường hợp đặc biệt của resolution
- Nhờ liên hệ với logic hình thức, có thể áp dụng gỡ lỗi khai báo dựa trên các tính chất logic của chương trình
- Khi thêm ràng buộc, tập nghiệm chỉ có thể thu hẹp lại
- Khi thêm mệnh đề, tập nghiệm chỉ có thể mở rộng ra
- Tính chất này của chương trình Prolog thuần túy được gọi là tính đơn điệu
- GUPU system của Ulrich Neumerkel là một ví dụ áp dụng các ý tưởng này
Tính homoiconic: coi chương trình như dữ liệu
- Chương trình Prolog cũng đồng thời là một term hợp lệ của Prolog
- Nhờ đặc tính này, chương trình Prolog rất dễ phân tích, biến đổi và diễn giải các chương trình Prolog khác
- Có thể đọc term Prolog bằng vị từ dựng sẵn
read/1, và vì vậy cũng có thể đọc các clause của Prolog
- Prolog có một cơ chế macro mạnh mẽ để tái viết chương trình tại thời điểm biên dịch
- Nhờ đó có thể hiện thực các ngôn ngữ đặc thù miền giúp giải quyết công việc một cách tự nhiên hơn
list_length(Ls,N) và N#>0 trông khác nhau về mặt ký pháp, nhưng chỉ là các cách biểu diễn dễ đọc hơn nhờ các toán tử tiền tố, trung tố và hậu tố trong Prolog
- Ví dụ, term Prolog
+(a,b) có thể được viết ở dạng toán tử là a+b
- Vì cú pháp trừu tượng là đồng nhất, có thể đọc và xử lý mọi term Prolog bất kể được viết theo cách nào
- Có thể định nghĩa động các toán tử do người dùng tạo cho từng mục đích cụ thể
Tính động ở runtime và khả năng mở rộng
- Chương trình Prolog có thể dễ dàng được tạo, được gọi và được sửa đổi ở runtime
- Đặc tính này làm tăng sức biểu đạt và cho phép hiện thực vị từ bậc cao nhận các vị từ khác làm tham số
- Cũng có thể hiện thực các kỹ thuật rất động như adaptive parsing
- Prolog phù hợp để viết các chương trình có thể được mở rộng bằng các quy tắc do lập trình viên khác hoặc người dùng phổ thông cung cấp
- Một trình thông dịch cho Prolog thuần túy có thể được định nghĩa chỉ bằng hai dòng mã Prolog
- Nội dung liên quan được trình bày trong A Couple of Meta-interpreters in Prolog
Phạm vi ứng dụng đa dạng và các cơ chế ngầm
- Bản chất quan hệ của Prolog khiến chương trình trở nên linh hoạt và tổng quát
- Đặc tính này đóng vai trò quan trọng trong việc biểu diễn tri thức cho xử lý ngôn ngữ và cơ sở dữ liệu
- Các hệ Prolog hiện đại cung cấp những tính năng cần thiết cho mọi thứ, từ các logic puzzles đơn giản đến các ứng dụng quy mô lớn
- Tính đa dụng và sức mạnh của Prolog bắt nguồn từ các cơ chế ngầm như tìm kiếm, hợp nhất, lập chỉ mục đối số và lan truyền ràng buộc
- Nhà phát triển có thể tận dụng các cơ chế này để giao nhiều công việc cho engine Prolog xử lý
1 bình luận
Ý kiến trên Hacker News
Tôi gần như hoàn toàn đồng ý với cảm nhận ở đây. Tôi đã dùng Prolog trong ba môn AI ở đại học, gần như học toàn bộ "AI: A Modern Approach" cùng lập trình Prolog, và đó thật sự là một trải nghiệm làm méo mó cách tư duy
Lúc nào tôi cũng cần khởi động lại để suy nghĩ theo kiểu Prolog, và trong học kỳ đó tôi còn viết cả mã spaghetti kinh khủng đậm chất Prolog bằng những ngôn ngữ khác. Nhược điểm lớn nhất lúc ấy là khả năng tương tác với những thứ khác khá khó, nên phải nhét Prolog vào trong JVM, dùng một bản triển khai ít tính năng hơn, hoặc dựa vào C binding. Nó rất tuyệt cho một số tác vụ nhất định, đặc biệt là các bài toán thỏa mãn ràng buộc, nhưng tôi thấy không phù hợp khi trộn thêm những thứ như giao diện người dùng hay truy cập hệ thống tệp. Khi đó SWI cũng còn tụt hậu và chúng tôi dùng các giải pháp độc quyền như Sicstus; lần gần đây kiểm tra lại thì SWI đã bắt kịp các bản triển khai độc quyền, nên nếu là bây giờ có lẽ tôi sẽ chọn SWI. Bài thi Prolog là đáng sợ nhất ở đại học: 3 bài live coding trong 60 phút rồi tiếp đó là thi vấn đáp, nhưng tôi đã vượt qua ổn khi mất 40 phút cho bài dễ rồi giải hai bài còn lại chỉ trong vài phút. Ở môn tiếp theo, bài tập triển khai tác tử chơi game để thi đấu trong một giải tournament khá thú vị, và "The Art of Prolog" cùng "The Craft of Prolog" nằm trong số những sách lập trình hay nhất tôi từng đọc
The Craft of Prolog cũng xuất sắc, nhưng quá chuyên biệt vào lập trình hệ thống Prolog đời cũ nên hiện có vài chương đã lỗi thời. Nhiều ý tưởng của Prolog vẫn sống trong answer set programming và Datalog, còn Datalog thì rất tuyệt để xây dựng các bộ phân tích tĩnh hiện đại: https://arxiv.org/abs/2012.10086
Tự nhiên tôi tò mò không biết chatbot sẽ xử lý Prolog thế nào. Chúng đã thấy đủ chưa? Chúng có thể suy luận theo cách đó không?
Prolog rất hay, và chỉ riêng niềm vui được trải nghiệm một paradigm lập trình lạ cũng đáng để học thử. Nhiều khái niệm được biểu diễn theo một cách hoàn toàn khác, và khi paradigm đó “ngấm” rồi thì mọi thứ lại trở nên đơn giản hơn nhiều
Ví dụ trong Prolog, thường bạn không thao tác trực tiếp với collection, mà cung cấp thông tin về các phần tử trong collection rồi để bản triển khai tự tìm ra. Vẽ cây phụ thuộc cũng có thể làm chỉ với 3 quy tắc: entity là gì, cách xác định quan hệ giữa entity X và Y, và cách biểu diễn nó. Tuy nhiên vì nó khó nên khó thuyết phục người khác học hoặc dùng, và tôi vẫn chưa tìm ra cách tích hợp nó thật mượt vào ứng dụng khác. Tôi biết FFI là một lựa chọn, nhưng chưa bị thuyết phục rằng nó đã sẵn sàng cho production. Trong vài tháng gần đây tôi đã tìm các lựa chọn thay thế Prolog “production” hơn, nhưng LispWorks hay Franz Allegro CL thì quá đắt và không thân thiện với tích hợp. Tôi thật sự tò mò nếu có ví dụ nào tích hợp Prolog tốt vào phần mềm hiện đại. XPCE không chạy trên Mac nên tôi cũng đang tìm giải pháp GUI. Swish dạng notebook online cũng đáng xem: https://swish.swi-prolog.org
Tôi nghe nói hiện nó đã bị gỡ bỏ, nên không phải ví dụ “hiện đại”, nhưng đây là một ví dụ thật sự đẹp về việc áp dụng Prolog. Rất đáng đọc theo mạch từ https://news.ycombinator.com/item?id=36821871 đến https://web.archive.org/web/20030218034509/http://www.resear.... Liên kết liên quan: https://news.ycombinator.com/item?id=14046420
Cả hai đều hoạt động khá tốt nhưng use case bị giới hạn. Trải nghiệm dùng Prolog ở đại học thì vui, nhưng nếu bài toán không mang bản chất đúng kiểu Prolog thì tôi không muốn dùng. Khi bắt đầu triển khai thứ hơi phức tạp, các abstraction rò rỉ liên tục, và cảm giác giống như đang vật lộn với thuật toán backtracking hơn là tận hưởng ưu điểm của ngôn ngữ
Racklog là Prolog-style logic programming được nhúng vào Racket, và “nhúng” nghĩa là bạn không mất Racket. Bạn có thể viết các đoạn mã kiểu Prolog song song với mã Racket thông thường. Nó chứa hầu hết các tính năng của Prolog, bao gồm meta-logic và các predicate “tập hợp” bậc hai, chỉ loại trừ những chức năng có thể làm dễ hơn và hiệu quả hơn bằng biểu thức con Racket. https://docs.racket-lang.org/racklog/index.html Racket cũng có GUI, và về cơ bản có gần như mọi thứ cần thiết
CUE dễ đưa vào workflow hiện có hơn nhiều, nên rất hợp để biến lợi ích của logic programming thành thứ thực dụng. https://cuelang.org | https://cuetorials.com
Trong vài năm làm phần mềm tối ưu hóa chuỗi cung ứng bằng C++, tôi đã dùng phần mềm lan truyền ràng buộc ILOG, Solver hiện thuộc sở hữu của IBM. Khi đó tôi cũng xem xét BinProlog; nó có lan truyền phạm vi tích hợp sẵn, biên dịch xuống x86 native và khả năng tương tác FFI cũng khá ổn
Dù vậy cuối cùng có vẻ nó đã bị SWI Prolog và GNU toolchain lấn át. GUI có lẽ nên được xem là một lĩnh vực chuyên môn hoàn toàn khác; chúng tôi dùng engine render canvas C++ tự viết và một công cụ phát triển 4GL tích hợp tệ hại tên là “4D” hoặc “Fourth Dimension”. https://www.tomshw.it/data/images/2/0/4/3/infor-advanced-sch...
Ngôn ngữ Shen của Mark Tarver có một bản triển khai Prolog đầy đủ: https://shenlanguage.org/SD/Prolog.html
Cũng có chương tương ứng trong The Book of Shen: https://shenlanguage.org/TBoS/tbos_359.html Tarver cũng viết hai cuốn sách kèm phần mềm về lập trình logic. Logic, Proof and Computation: https://shenlanguage.org/lpc.html Programming the Logic Lab: https://shenlanguage.org/logiclab.html
Pattern matching, kiểm tra kiểu tùy chọn, Prolog tích hợp sẵn — tất cả đều đáng kinh ngạc. Người sáng lập phần nào bị cộng đồng rộng hơn xa lánh vì thái độ ngoại giao của mình, nhưng ông ấy rất xuất sắc, còn mức độ áp dụng thì vẫn mang tính ngách và tiên phong. Nếu có một tổ chức như Mozilla đứng sau, có lẽ nó đã hấp dẫn đại chúng hơn nhiều. Các bài nói của @deech giờ đã cũ nhưng vẫn tuyệt vời và còn ý nghĩa: https://www.youtube.com/watch?v=lMcRBdSdO_U, https://www.youtube.com/watch?v=BUJNyHAeAc8 tuy nhiên hãy lưu ý là tôi là fan cuồng APL/J/BQN
Tôi còn nhớ mình đã học Prolog trong chương trình bằng AI + khoa học máy tính khoảng 25 năm trước. Dùng khá nhiều trong module xử lý ngôn ngữ tự nhiên
Ban đầu rất bức bối và khó chịu, nhưng khi quen rồi thì bất ngờ là khá thú vị; vì cách duy nhất để lặp là đệ quy, nên nó cũng là một cách nhập môn đệ quy rất tốt
Ở đại học, chúng tôi học Prolog chủ yếu từ các nhà toán học chỉ dùng kiểu ngôn ngữ như vậy, và với họ Prolog là một lối tư duy rất tự nhiên. Ngược lại, với những sinh viên vốn chủ yếu dùng ngôn ngữ thủ tục, nó rất rối rắm và bực bội; ai cũng cố viết Prolog như một ngôn ngữ khác rồi bị mắc kẹt. Mãi đến môn thứ ba hoặc thứ tư dùng Prolog, sau khi học các thuật toán phía sau nó, tôi mới bắt đầu hiểu cách dùng cho đúng. Về sau tôi từng giúp một sinh viên đại học đang vật lộn với Prolog; điểm mấu chốt là không cố bắt Prolog hoạt động như các ngôn ngữ quen thuộc, mà phải đổi cách nghĩ giải quyết vấn đề cho phù hợp với thế giới Prolog. Sau một cuộc nói chuyện khá dài, cậu ấy có khoảnh khắc thật sự “ngộ ra” và hoàn thành bài tập rất tốt
Nhưng khi paradigm mới ấy khớp hẳn trong đầu, tôi thật sự thích nó. Chỉ riêng khoảnh khắc ngộ ra đó đã đủ làm cho khóa học đáng học
Các bình luận khác nói về Prolog nói chung, nhưng tôi muốn nói rằng The Power of Prolog là một series hướng dẫn khá xuất sắc
Video cũng đáng xem, và Markus rất biết cách giữ sự hứng thú của người xem và độc giả
Nhờ video này mà tôi nhìn nhận Prolog như một chuyển động đang tiếp diễn và tiến bộ trong lập trình
Prolog là một ngôn ngữ đẹp. Tôi đã viết hàng chục nghìn dòng cho suy luận toán học, suy luận dựa trên luật, v.v.; với các lĩnh vực đó nó khớp hoàn hảo và làm việc với nó cực kỳ vui
Với các loại ứng dụng khác thì có hai vấn đề. Thứ nhất, paradigm quá khác nên không ăn khớp tốt với thư viện và các ngôn ngữ khác. Thứ hai, gần như không thể làm một GUI tử tế, cũng vì nó không hợp với paradigm đó
Thông thường, phía Prolog sẽ thấy interface bên ngoài như một predicate mà mọi đối số đều đã được ground, còn phía bên ngoài thì tương tác với Prolog như làm việc với một cơ sở dữ liệu SQL. Gửi truy vấn, phân rã truy vấn, yêu cầu thêm nghiệm hoặc điều khiển backtracking. Có thể nói kiểu tương tác này “không thú vị”, nhưng nó hoạt động như vậy vì các thư viện không thật sự tận dụng những tính năng hữu ích của Prolog. Nếu muốn, có thể xây dựng một lớp tương tác dày hơn, gom nhiều hàm thư viện thành một interface predicate duy nhất ở phía Prolog rồi gọi các subroutine cụ thể tùy theo chế độ khởi tạo của đối số. Nhưng việc này cũng không khác nhiều so với khi phơi bày một thư viện C cho một ngôn ngữ hướng đối tượng như Python, bằng cách gom nhiều hàm C thành các accessor thuộc tính hoặc method của cấu trúc dữ liệu
Tôi đang tích cực dùng Prolog cho phân tích dữ liệu. Ban đầu cần có một giai đoạn tự ép mình làm mọi thứ có thể bằng Prolog để hiểu cách chuyển câu hỏi thành bài toán ký hiệu
Prolog là vì khả năng hỗ trợ tính toán khoa học và thao tác chuỗi của nó rất tệ. Một khi vượt qua giai đoạn đó, giải pháp bằng Prolog thường thanh nhã hơn phương án tốt kế tiếp. Ngoài ra, vì đây là một mô thức logic, nên rất đáng dành thời gian để hiểu quá trình chứng minh bằng phủ định + hợp nhất = lập trình logic. Trong số các ngôn ngữ lập trình tôi từng học, đây chắc chắn là ngôn ngữ mở rộng tầm nhìn của tôi nhiều nhất
Prolog chuẩn không tích hợp sẵn biểu thức chính quy, nhưng các triển khai phổ biến thường cung cấp thư viện cho việc này. Nếu phải làm nhiều việc với chuỗi và phải chọn giữa C và Prolog thì chắc chắn tôi sẽ chọn Prolog. Còn giữa Python và Prolog thì tùy vào công việc
Dù sao thì đây là một trang tuyệt vời, và tôi rất vui khi chủ đề này được nhắc lại
Trước đó tôi từng viết một trình giải bằng Java, nên tôi cố chuyển code đó sang Prolog nhưng hoàn toàn không hiệu quả. Cuối cùng tôi bắt đầu lại từ đầu, viết một đoạn Prolog đơn giản để kiểm tra Sudoku có hợp lệ hay không, rồi nhận ra rằng nếu chạy các vị từ đó thì cũng có thể giải được Sudoku. Thế là tôi hoàn thành trình giải trong chưa đến 10 dòng. Đó thật sự là một khoảnh khắc eureka, và Prolog rất mạnh mẽ nhưng lại bị dùng ít một cách bất công trong thực tế. May mắn là tôi đã có cơ hội làm việc với Datalog và OWL