Во-первых, позвольте мне поздравить вас с прекрасным значком pw0n1e.
На этот вопрос сложно ответить, в основном потому, что существует множество вариантов как miniKanren, так и Prolog. miniKanren и Prolog - это действительно семейства языков, что затрудняет сравнение их возможностей или даже того, как они используются на практике. Из-за этого, пожалуйста, относитесь ко всему, что я собираюсь сказать, с осторожностью: если я скажу, что Prolog использует поиск в глубину, имейте в виду, что многие реализации Prolog поддерживают другие стратегии поиска, и что альтернативные стратегии поиска также могут быть закодированы в мета -уровень переводчика. Тем не менее, miniKanren и Prolog придерживаются разных принципов проектирования и идут на разные компромиссы.
Пролог - один из двух классических языков программирования символического искусственного интеллекта (другим классическим языком является Лисп). Prolog превосходно реализует символьные системы на основе правил, в которых декларативные знания закодированы в логике первого порядка. Язык оптимизирован для выразительности и эффективности для этих типов приложений, иногда за счет логической чистоты. Например, по умолчанию Пролог не использует "проверку на наличие" в унификации. С точки зрения математики и логики эта версия унификации неверна. Однако проверка срабатывания обходится дорого, и в большинстве случаев отсутствие проверки срабатывания не является проблемой. Это очень прагматичное дизайнерское решение, так же как и использование Prolog поиска в глубину и использование cut (!
) для управления возвратом. Я уверен, что эти решения были абсолютно необходимы при работе на оборудовании 1970-х годов, а сегодня они очень полезны при работе над большими проблемами и при работе с огромными (часто бесконечными!) Пространствами поиска.
Prolog поддерживает множество «экстра-логических» или «нелогических» функций, в том числе вырезание assert
и retract
проекция переменных для арифметики с использованиемis
, и так далее. Многие из этих функций упрощают выражение сложного потока управления и управление глобальной базой данных Prolog. Одна очень интересная особенность Пролога заключается в том, что код Пролога сам хранится в глобальной базе данных фактов, и его можно запрашивать во время выполнения. Это делает тривиальным написание мета-интерпретаторов, которые изменяют поведение кода Пролога при интерпретации. Например, в Прологе можно кодировать поиск в ширину с помощью метаинтерпретатора, который изменяет порядок поиска. Это чрезвычайно мощный метод, малоизвестный за пределами мира Пролога. «Искусство Пролога» подробно описывает эту технику.
Огромные усилия были вложены в улучшение реализаций Пролога, большинство из которых основано на абстрактной машине Уоррена (WAM). WAM использует модель побочных эффектов, в которой значения деструктивно присваиваются логическим переменным, причем эти побочные эффекты отменяются при возврате. Многие функции могут быть добавлены в Prolog путем расширения инструкций WAM. Одним из недостатков этого подхода является то, что документы по реализации Prolog могут быть трудночитаемыми без твердого понимания WAM. С другой стороны, у разработчиков Prolog есть общая модель для обсуждения вопросов реализации. Параллельно с Prolog было проведено множество исследований, кульминацией которых стал Andorra Prolog в 1990-х годах. По крайней мере, некоторые из этих идей живут в Ciao Prolog. (Ciao Prolog полон интересных идей, многие из которых выходят далеко за рамки стандарта Prolog.)
В Prolog есть прекрасный синтаксис в стиле «сопоставления с образцом», основанный на унификации, что позволяет создавать очень сжатые программы. Прологеры любят свой синтаксис, так же как лисперы любят свои s-выражения. В Prolog также есть большая библиотека стандартных предикатов. Благодаря всем инженерным разработкам, направленным на то, чтобы сделать WAM быстрым, существуют очень эффективные и зрелые реализации Prolog. В результате многие большие системы, основанные на знаниях, были полностью написаны на Прологе.
miniKanren был разработан как язык программирования с минимальной логикой, с небольшой, легко понятной и легко взломанной реализацией. miniKanren изначально был встроен в Scheme, а за последнее десятилетие был перенесен на десятки других основных языков. Самая популярная реализация miniKanren - это core.logic в Clojure, который теперь имеет множество расширений, подобных Prolog, и ряд оптимизаций. Недавно ядро реализации miniKanren было еще больше упрощено, в результате появилось крошечное «микроядро» под названием «microKanren». Затем miniKanren можно реализовать поверх этого ядра microKanren. Перенос microKanren или miniKanren на новый основной язык стал стандартным упражнением для программистов, изучающих miniKanren. В следствии,
Стандартные реализации miniKanren и microKanren не содержат мутаций или других побочных эффектов, за одним исключением: некоторые версии miniKanren используют равенство указателей для сравнения логических переменных. Я считаю это «благоприятным эффектом», хотя многие реализации избегают даже этого эффекта, передавая счетчик через реализацию. Также нет глобальной базы данных фактов. Философия реализации miniKanren основана на функциональном программировании: следует избегать мутаций и эффектов, а все языковые конструкции должны учитывать лексическую область видимости. Если вы внимательно посмотрите на реализацию, вы можете даже заметить пару монад. Реализация поиска основана на объединении и управлении ленивыми потоками, опять же без использования мутации. Эти варианты реализации приводят к совершенно другим компромиссам, чем в Prolog. В Прологе поиск переменных - это постоянное время, но для поиска с возвратом требуется устранение побочных эффектов. В miniKanren поиск переменных обходится дороже, но поиск с возвратом «бесплатный». Фактически, в miniKanren нет возврата с возвратом из-за того, как обрабатываются потоки.
Один интересный аспект реализации miniKanren состоит в том, что код по своей сути является потокобезопасным и - по крайней мере теоретически - легко распараллеливается. Конечно, распараллеливание кода без его замедления - нетривиальная задача, учитывая, что каждому потоку или процессу нужно дать достаточно работы, чтобы компенсировать накладные расходы на распараллеливание. Тем не менее, это область реализации miniKanren, которая, я надеюсь, получит больше внимания и экспериментов.
miniKanren использует проверку возникновения для унификации и использует полный поиск с чередованием вместо поиска в глубину. Поиск с чередованием использует больше памяти, чем поиск в глубину, но может найти ответы в некоторых случаях, когда поиск в глубину будет расходиться / зацикливаться навсегда. miniKanren делает поддержку несколько экстра-логические операторы --- conda
, condu
и project
, к примеру. conda
и condu
может использоваться для имитации сокращения Пролога и project
может использоваться для получения значения, связанного с логической переменной.
Наличие conda
,condu
иproject
--- и возможность легко изменять стратегию поиска --- позволяет программистам использовать miniKanren как встроенный язык, подобный Prolog. Это особенно верно для пользователей Clojure core.logic, который включает множество расширений, подобных Prolog. Это «прагматичное» использование miniKanren, кажется, составляет большую часть использования miniKanren в промышленности. Программисты, которые хотят добавить систему рассуждений, основанную на знаниях, в существующее приложение, написанное на Clojure, Python или JavaScript, обычно не заинтересованы в переписывании всего своего приложения на Prolog. Встраивание небольшого языка логического программирования в Clojure или Python гораздо привлекательнее. Предположительно, для этой цели подойдет и встроенная реализация Пролога.
В дополнение к использованию miniKanren в качестве прагматичного языка программирования встроенной логики, аналогичного по духу Prolog, miniKanren используется для исследований в области «реляционного» программирования. То есть при написании программ, которые ведут себя как математические отношения, а не как математические функции. Например, в Scheme append
функция может добавлять два списка, возвращая новый список: вызов функции (append '(a b c) '(d e))
возвращает список (a b c d e)
. Однако мы можем рассматривать его append
как трехместное отношение, а не как функцию с двумя аргументами. Затем вызов (appendo '(a b c) '(d e) Z)
связывает логическую переменную Z
со списком (a b c d e)
. Конечно, все становится интереснее, когда мы помещаем логические переменные в другие позиции. Звонок (appendo X '(d e) '(a b c d e))
ассоциируется X
с (a b c)
, а звонок(appendo X Y '(a b c d e))
партнерамиX
и Y
с парами списков, которые при добавлении равны (a b c d e)
. Например, X
= (a b)
и Y
= (c d e)
- одна такая пара значений. Мы также можем написать (appendo X Y Z)
, что будет производить бесконечно много троек списков X
, Y
и Z
таким образом, что добавление X
к Y
производят Z
.
Эту реляционную версию append
можно легко выразить в Prolog, и она действительно показана во многих руководствах по Prolog. На практике более сложные программы на Прологе имеют тенденцию использовать по крайней мере несколько дополнительных логических функций, таких как вырезание, которые препятствуют возможности обработки полученной программы как отношения. Напротив, miniKanren специально разработан для поддержки этого стиля реляционного программирования. Более поздние версии miniKanren поддерживают решение символических ограничений ( symbolo
,numbero
,absento
, ограничения неравенства, номинальное логическое программирование), чтобы упростить написание нетривиальных программ в виде отношений. На практике я никогда не использую никаких дополнительных логических функций miniKanren и пишу все свои программы miniKanren как отношения. Самые интересные реляционные программы - это реляционные интерпретаторы для подмножества Scheme. Эти интерпретаторы обладают множеством интересных способностей, таких как создание миллиона программ Scheme, оценивающих список (I love you)
, или тривиального создания quines (программ, которые оценивают сами себя).
miniKanren делает ряд компромиссов, чтобы реализовать этот реляционный стиль программирования, которые сильно отличаются от компромиссов, которые делает Пролог. Со временем miniKanren добавил больше символических ограничений, фактически став символьно-ориентированным языком программирования логических ограничений. Во многих случаях эти символические ограничения позволяют избежать использования дополнительных логических операторов, таких как condu
и project
. В других случаях этих символических ограничений недостаточно. Лучшая поддержка символических ограничений - одна из активных областей исследований miniKanren, наряду с более широким вопросом о том, как писать более крупные и сложные программы как отношения.
Короче говоря, и miniKanren, и Prolog имеют интересные особенности, реализации и способы использования, и я думаю, что стоит изучить идеи обоих языков. Есть и другие очень интересные языки логического программирования, такие как Mercury, Curry и Gödel, каждый из которых имеет свой собственный подход к логическому программированию.
Я закончу несколькими ресурсами miniKanren:
Главный сайт miniKanren:
http://minikanren.org/
Интервью, которое я дал о реляционном программировании и miniKanren, включая сравнение с Prolog:
http://www.infoq.com/interviews/byrd-relational-programming-minikanren
Ура,
--Будет