3 điểm bởi GN⁺ 2023-09-14 | 1 bình luận | Chia sẻ qua WhatsApp
  • 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 N0N 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)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
    • ProloxyGerrit Code Review là các ví dụ xây dựng yêu cầu bằng các quy tắc Prolog linh hoạt và dễ đọc
  • 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ữ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

 
GN⁺ 2023-09-14
Ý 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

    • Tôi xem The Art of Prolog là kinh điển của lập trình kiểu động, cùng với Concepts, Techniques, and Models of Computer Programming, Paradigms of AI Programming, Structure and Interpretation of Computer Programs
      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ôi vẫn còn nhớ vẻ mặt của các sinh viên đại học bước ra sau buổi giảng Prolog đầu tiên. Một nửa là sốc, một nửa là lo lắng
      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?
    • Tôi không hiểu sao nó lại khó đến vậy. Chẳng phải chỉ là tìm kiếm theo chiều sâu biến thành ngôn ngữ thôi sao
  • 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

    • Không phải câu trả lời trực tiếp, nhưng David Hovell đã dùng Prolog để cưỡng chế tính nhất quán của thiết lập mạng Windows NT
      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
    • Không biết cái này có tính không, nhưng predicate submit của Gerrit từng được cấu hình bằng Prolog và giờ đang được lên kế hoạch loại bỏ. Một sản phẩm nội bộ mà tôi từng làm ở Google được xây quanh một knowledge base Datalog sinh mã, có thể truy vấn trực tiếp hoặc tạo truy vấn qua UI
      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ữ
    • Racket có Racklog
      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
    • Dạo này người ta cũng nói điều tương tự về CUE. Nó là một công cụ khá làm đảo lộn tư duy, nhưng cho ta một cách mới để kiểm soát độ phức tạp của cấu hình và schema
      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

    • Tôi thích Shen nhưng chưa đào sâu đến nơi đến chốn. Tôi đã đăng ký bản Professional trong nửa năm và thích các implementation của Shen được xây dựng trên nhiều ngôn ngữ lập trình khác nhau
      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

    • Một trong những điều Prolog dạy tôi là tầm quan trọng của người thầy có thể đứng ở góc nhìn của sinh viên
      Ở đạ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
    • Tôi cũng tương tự. Ban đầu tôi cố viết mã mệnh lệnh bằng cú pháp Prolog nên thấy bức bối và khó chịu
      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ó lẽ nói “cũng là một cách nhập môn đệ quy rất tốt, vì đó là cách duy nhất để đệ quy” sẽ chính xác hơn
    • Vài năm trước trong chương trình cử nhân khoa học máy tính tôi cũng học Prolog. Tuy không chiếm tỷ trọng lớn, chỉ là một phần nhỏ của môn AI, nhưng vẫn rất thú vị
  • 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ả

    • Từ góc nhìn của một người từng thất vọng với Prolog lúc đầu rồi sau đó có khoảnh khắc “ngộ ra”, tôi khuyên nên bắt đầu với video Preparing Prolog của Markus: https://www.metalevel.at/prolog/videos/preparing_prolog
      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 đó

    • Tôi từng tham gia viết phần tương tác với Go của GoLog, và việc giao tiếp với các ngôn ngữ khác không hẳn là khó
      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

  • Khả năng hỗ trợ thao tác chuỗi của Prolog khá ổn. Hầu như không có ngôn ngữ phổ biến hiện đại nào cung cấp sẵn những thứ như DCG làm mặc định
    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
  • Thú vị đấy, bạn có thể cho một ví dụ về cách dùng nó trong phân tích dữ liệu không?
  • Chủ đề này cũng đã được thảo luận 1 năm trước: https://news.ycombinator.com/item?id=31641014
    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
  • 10 dòng triển khai tìm kiếm đồ thị A* bằng Prolog là 10 dòng code khó nhất trong đời tôi
  • Hồi đại học tôi từng học một lớp Prolog. Chúng tôi phải triển khai một trình giải Sudoku, và đến một lúc thì tôi bị mắc kẹt
    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