Đầu tiên, cho phép tôi khen ngợi bạn về biểu tượng pw0n1e đẹp của bạn.
Đây là một câu hỏi khó trả lời, phần lớn là do có rất nhiều biến thể của cả miniKanren và Prolog. miniKanren và Prolog thực sự là họ ngôn ngữ, điều này gây khó khăn cho việc so sánh các tính năng của chúng hoặc thậm chí cách chúng được sử dụng trong thực tế. Vì lý do này, hãy thận trọng với mọi điều tôi sắp nói: nếu tôi nói rằng Prolog sử dụng tìm kiếm theo chiều sâu, hãy lưu ý rằng nhiều triển khai Prolog hỗ trợ các chiến lược tìm kiếm khác và các chiến lược tìm kiếm thay thế cũng có thể được mã hóa theo meta -cấp độ thông dịch viên. Tuy nhiên, miniKanren và Prolog có các triết lý thiết kế khác nhau và thực hiện các đánh đổi khác nhau.
Prolog là một trong hai ngôn ngữ cổ điển để lập trình trí tuệ nhân tạo tượng trưng (ngôn ngữ cổ điển khác là Lisp). Prolog vượt trội trong việc triển khai các hệ thống dựa trên quy tắc tượng trưng trong đó kiến thức khai báo được mã hóa theo logic bậc nhất. Ngôn ngữ được tối ưu hóa để diễn đạt và hiệu quả cho các loại ứng dụng này, đôi khi phải trả giá bằng sự thuần túy logic. Ví dụ, theo mặc định Prolog không sử dụng "kiểm tra xảy ra" trong hợp nhất. Từ quan điểm toán học / logic, phiên bản hợp nhất này không chính xác. Tuy nhiên, việc kiểm tra xảy ra rất tốn kém, và trong hầu hết các trường hợp, việc thiếu kiểm tra xảy ra không phải là vấn đề. Đây là một quyết định thiết kế rất thực dụng, cũng như việc Prolog sử dụng tìm kiếm theo chiều sâu và sử dụng phương pháp cắt (!
) để kiểm soát backtracking. Tôi chắc chắn rằng những quyết định này là hoàn toàn cần thiết khi chạy trên phần cứng của những năm 1970 và ngày nay rất hữu ích khi giải quyết các vấn đề lớn và khi xử lý không gian tìm kiếm khổng lồ (thường là vô hạn!).
Prolog hỗ trợ nhiều tính năng "bổ sung logic" hoặc "phi logic", bao gồm cắt assert
và retract
chiếu các biến số học bằng cách sử dụngis
, và kể từ đó trở đi. Nhiều tính năng trong số này giúp dễ dàng hơn trong việc diễn đạt luồng điều khiển phức tạp và thao tác với cơ sở dữ liệu toàn cầu của Prolog. Một tính năng rất thú vị của Prolog là bản thân mã Prolog được lưu trữ trong cơ sở dữ liệu toàn cầu về dữ kiện và có thể được truy vấn tại thời điểm chạy. Điều này làm cho việc viết các trình thông dịch meta sửa đổi hành vi của mã Prolog theo cách diễn giải là trở nên tầm thường. Ví dụ: có thể mã hóa tìm kiếm theo chiều rộng trong Prolog bằng cách sử dụng trình thông dịch meta thay đổi thứ tự tìm kiếm. Đây là một kỹ thuật cực kỳ mạnh mẽ mà không được biết đến nhiều bên ngoài thế giới Prolog. 'The Art of Prolog' mô tả chi tiết kỹ thuật này.
Nỗ lực to lớn đã được dành để cải thiện việc triển khai Prolog, hầu hết trong số đó dựa trên Máy trừu tượng Warren (WAM). WAM sử dụng một mô hình hiệu ứng phụ, trong đó các giá trị được gán một cách triệt tiêu cho các biến logic, với những tác động phụ này sẽ được hoàn tác khi bẻ khóa lại. Nhiều tính năng có thể được thêm vào Prolog bằng cách mở rộng hướng dẫn của WAM. Một nhược điểm của phương pháp này là các tài liệu triển khai Prolog có thể khó đọc nếu không có hiểu biết vững chắc về WAM. Mặt khác, người triển khai Prolog có một mô hình chung để thảo luận về các vấn đề triển khai. Đã có rất nhiều nghiên cứu về Prolog song song, đỉnh cao là Andorra Prolog vào những năm 1990. Ít nhất một số ý tưởng trong số này vẫn tồn tại trong Ciao Prolog. (Ciao Prolog chứa đầy những ý tưởng thú vị, nhiều ý tưởng trong số đó vượt xa tiêu chuẩn của Prolog.)
Prolog có cú pháp kiểu "khớp mẫu" dựa trên thống nhất tuyệt đẹp, dẫn đến các chương trình rất ngắn gọn. Người mở đầu yêu thích cú pháp của họ, giống như Lispers yêu thích biểu thức s của họ. Prolog cũng có một thư viện lớn các vị từ chuẩn. Do tất cả các kỹ thuật đã được đưa vào làm cho WAM nhanh chóng, có những triển khai Prolog rất có khả năng và trưởng thành. Kết quả là, nhiều hệ thống dựa trên tri thức lớn đã được viết hoàn toàn bằng Prolog.
miniKanren được thiết kế như một ngôn ngữ lập trình logic tối thiểu, với cách triển khai nhỏ gọn, dễ hiểu và dễ hack. miniKanren ban đầu được nhúng trong Scheme và đã được chuyển sang hàng chục ngôn ngữ chủ khác trong thập kỷ qua. Việc triển khai miniKanren phổ biến nhất là 'core.logic' trong Clojure, hiện có nhiều phần mở rộng giống Prolog và một số tối ưu hóa. Gần đây, cốt lõi của việc triển khai miniKanren đã được đơn giản hóa hơn nữa, dẫn đến một "hạt nhân siêu nhỏ" được gọi là "microKanren." miniKanren sau đó có thể được thực hiện trên đầu của lõi microKanren này. Việc chuyển microKanren hoặc miniKanren sang một ngôn ngữ máy chủ mới đã trở thành một bài tập tiêu chuẩn cho các lập trình viên học miniKanren. Kết quả là,
Các triển khai tiêu chuẩn của miniKanren và microKanren không chứa đột biến hoặc các tác dụng phụ khác, với một ngoại lệ duy nhất: một số phiên bản của miniKanren sử dụng bình đẳng con trỏ để so sánh các biến logic. Tôi coi đây là một "hiệu ứng lành tính", mặc dù nhiều cách triển khai thậm chí tránh được hiệu ứng này bằng cách chuyển một bộ đếm thông qua việc triển khai. Cũng không có cơ sở dữ liệu thực tế toàn cầu. Triết lý triển khai của miniKanren được lấy cảm hứng từ lập trình chức năng: nên tránh đột biến và các hiệu ứng và tất cả các cấu trúc ngôn ngữ phải tôn trọng phạm vi từ vựng. Nếu bạn xem xét kỹ lưỡng việc triển khai, bạn thậm chí có thể phát hiện ra một vài monads. Việc triển khai tìm kiếm dựa trên việc kết hợp và thao tác các luồng lười biếng, một lần nữa mà không sử dụng đột biến. Những lựa chọn triển khai này dẫn đến sự đánh đổi rất khác so với trong Prolog. Trong Prolog, tra cứu biến là thời gian không đổi, nhưng theo dõi ngược lại yêu cầu hoàn tác các tác dụng phụ. Trong miniKanren, tra cứu biến số đắt hơn, nhưng theo dõi ngược lại là "miễn phí". Trên thực tế, không có backtracking trong miniKanren, do cách các luồng được xử lý.
Một khía cạnh thú vị của việc triển khai miniKanren là mã vốn dĩ an toàn theo luồng và --- ít nhất là về lý thuyết --- có thể song song hóa một cách đáng kể. Tất nhiên, song song mã mà không làm cho nó chậm hơn không phải là chuyện nhỏ, vì mỗi luồng hoặc quy trình phải được thực hiện đủ công việc để bù đắp cho chi phí của quá trình song song. Tuy nhiên, đây là một lĩnh vực triển khai miniKanren mà tôi hy vọng sẽ nhận được nhiều sự quan tâm và thử nghiệm hơn.
miniKanren sử dụng kiểm tra xảy ra để hợp nhất và sử dụng tìm kiếm xen kẽ hoàn chỉnh thay vì tìm kiếm theo chiều sâu. Tìm kiếm xen kẽ sử dụng nhiều bộ nhớ hơn tìm kiếm theo chiều sâu, nhưng có thể tìm thấy câu trả lời trong một số trường hợp mà tìm kiếm theo chiều sâu sẽ phân kỳ / lặp lại mãi mãi. miniKanren không hỗ trợ một vài nhà khai thác ngoài logic --- conda
, condu
và project
, ví dụ. conda
vàcondu
có thể được sử dụng để mô phỏng quá trình cắt của Prolog, và project
có thể được sử dụng để lấy giá trị liên kết với một biến logic.
Sự hiện diện của conda
,condu
vàproject
--- và khả năng dễ dàng sửa đổi chiến lược tìm kiếm --- cho phép các lập trình viên sử dụng miniKanren như một ngôn ngữ giống như Prolog được nhúng. Điều này đặc biệt đúng đối với người dùng 'core.logic' của Clojure, bao gồm nhiều phần mở rộng giống như Prolog. Việc sử dụng miniKanren "thực dụng" này dường như chiếm phần lớn việc sử dụng miniKanren trong ngành công nghiệp. Các lập trình viên muốn thêm hệ thống lý luận dựa trên kiến thức vào một ứng dụng hiện có được viết bằng Clojure hoặc Python hoặc JavaScript thường không quan tâm đến việc viết lại toàn bộ ứng dụng của họ trong Prolog. Nhúng một ngôn ngữ lập trình logic nhỏ trong Clojure hoặc Python hấp dẫn hơn nhiều. Có lẽ, một triển khai Prolog nhúng sẽ hoạt động tốt cho mục đích này.
Ngoài việc sử dụng miniKanren như một ngôn ngữ lập trình logic nhúng thực dụng tương tự như tinh thần của Prolog, miniKanren đang được sử dụng để nghiên cứu trong lập trình "quan hệ". Đó là, trong việc viết các chương trình hoạt động như các quan hệ toán học hơn là các hàm toán học. Ví dụ, trong Scheme, append
hàm có thể nối hai danh sách, trả về một danh sách mới: lệnh gọi hàm (append '(a b c) '(d e))
trả về danh sách (a b c d e)
. Tuy nhiên, chúng ta cũng có thể coi append
là một quan hệ ba vị trí hơn là một hàm hai đối số. Sau đó, lệnh gọi (appendo '(a b c) '(d e) Z)
sẽ liên kết biến logic Z
với danh sách (a b c d e)
. Tất nhiên mọi thứ trở nên thú vị hơn khi chúng ta đặt các biến logic ở các vị trí khác. Cuộc gọi (appendo X '(d e) '(a b c d e))
liên kết X
với các cộng sự(a b c)
, trong khi cuộc gọi(appendo X Y '(a b c d e))
X
vàY
với các cặp danh sách, khi được thêm vào, bằng (a b c d e)
. Ví dụ X
= (a b)
và Y
= (c d e)
là một trong những cặp giá trị như vậy. Chúng tôi cũng có thể viết (appendo X Y Z)
, mà sẽ tạo ra vô cùng nhiều gấp ba danh sách X
, Y
và Z
như vậy mà phụ thêm X
để Y
sản xuấtZ
.
Phiên bản quan hệ này của append
có thể dễ dàng được thể hiện trong Prolog và thực sự được hiển thị trong nhiều hướng dẫn Prolog. Trong thực tế, các chương trình Prolog phức tạp hơn có xu hướng sử dụng ít nhất một vài tính năng bổ sung logic, chẳng hạn như cắt, ngăn cản khả năng coi chương trình kết quả là một quan hệ. Ngược lại, miniKanren được thiết kế rõ ràng để hỗ trợ kiểu lập trình quan hệ này. Các phiên bản mới hơn của miniKanren có hỗ trợ giải quyết ràng buộc tượng trưng (symbolo
, numbero
,absento
, các ràng buộc bất bình đẳng, lập trình logic danh nghĩa) để giúp viết các chương trình không tầm thường dưới dạng quan hệ dễ dàng hơn. Trong thực tế, tôi không bao giờ sử dụng bất kỳ tính năng logic nào của miniKanren, và tôi viết tất cả các chương trình miniKanren của mình dưới dạng quan hệ. Các chương trình quan hệ thú vị nhất là các trình thông dịch quan hệ cho một tập hợp con của Đề án. Những người phiên dịch này có nhiều khả năng thú vị, chẳng hạn như tạo ra một triệu chương trình Đề án đánh giá danh sách (I love you)
, hoặc tạo ra các câu hỏi tầm thường (các chương trình tự đánh giá).
miniKanren thực hiện một số đánh đổi để kích hoạt kiểu lập trình quan hệ này, rất khác với kiểu đánh đổi mà Prolog thực hiện. Theo thời gian miniKanren đã thêm nhiều ràng buộc biểu tượng hơn, thực sự trở thành một ngôn ngữ Lập trình Logic Ràng buộc theo định hướng biểu tượng. Trong nhiều trường hợp, những ràng buộc tượng trưng này làm cho nó thực tế để tránh sử dụng các toán tử phụ logic như condu
và project
. Trong các trường hợp khác, những ràng buộc tượng trưng này là không đủ. Hỗ trợ tốt hơn cho các ràng buộc tượng trưng là một lĩnh vực tích cực của nghiên cứu miniKanren, cùng với câu hỏi rộng hơn là làm thế nào để viết các chương trình lớn hơn và phức tạp hơn dưới dạng quan hệ.
Tóm lại, cả miniKanren và Prolog đều có các tính năng, cách triển khai và cách sử dụng thú vị, và tôi nghĩ rất đáng để học hỏi ý tưởng từ cả hai ngôn ngữ. Ngoài ra còn có các ngôn ngữ lập trình logic rất thú vị khác, chẳng hạn như Mercury, Curry và Gödel, mỗi ngôn ngữ có nhiệm vụ riêng về lập trình logic.
Tôi sẽ kết thúc với một số tài nguyên miniKanren:
Trang web miniKanren chính:
http://minikanren.org/
Một cuộc phỏng vấn tôi đã đưa ra về lập trình quan hệ và miniKanren, bao gồm cả so sánh với Prolog:
http://www.infoq.com/interviews/byrd-relational-programming-minikanren
Chúc mừng,
--Sẽ