Модуль расширения целей, передаваемых в библиотечные мета-предикаты
Используя SWI-Prolog (многопоточный, 64 бита, версия 7.3.5), мы продвигаемся шаг за шагом:
Определить DCG нетерминал
a//1
в модулеdcgAux
(произносится: " ди-с-го "):: - модуль (dcgAux,[a//1]). a(0) -> []. a(s(N)) -> [a], a(N).
Запустите следующие запросы, используя
phrase/2
а такжеapply:foldl/4
:?- use_module ([библиотека (применить),dcgAux]). правда.?- фраза ( foldl( a,[s(0),s(s(0))]),[a,a,a]). правда?- фраза ( foldl(dcgAux:a,[s(0),s(s(0))]),[a,a,a]). правда?- фраза (применимо:foldl(dcgAux:a,[s(0),s(s(0))]),[a,a,a]). правда?- фраза (применимо:foldl( a,[s(0),s(s(0))]),[a,a,a]). ОШИБКА: применимо:foldl_/4: неопределенная процедура: применимо: a / 3
нет! Совершенно неожиданно, но не очень. Мы пропустили некоторые неизвестные неизвестные?
Чтобы избавиться от вышеупомянутого раздражающего поведения, мы должны сначала выяснить причину (ы), вызывающую его:
?- import_module (применить,M), M= пользователь. ложь?- фраза (применимо:foldl( a,[s(0),s(s(0))]),[a,a,a]). ОШИБКА: применимо:foldl_/4: неопределенная процедура: применимо:a/3?- add_import_module(применить, пользователь, конец). правда.?- import_module(применить,M), M= пользователь. % sic! М = пользователь. % `?- import_module(применить, пользователь).` не удалось!?- фраза (применимо:foldl( a,[s(0),s(s(0))]),[a,a,a]). правда
В чем дело? Я вижу это так:
- Модуль расширения цели передан
foldl/4
ограничено. Цитирование со страницы руководства SWI-Prolog на
import_module/2
:Все обычные модули импортируют только от пользователя, который импортирует из системы.
SWI-х
library(apply)
только "наследует" отsystem
, но нетuser
,Если мы клонируем модуль
apply
вapplY
(и распространяем имя нового модуля), мы наблюдаем:?- use_module (applY). правда.?- фраза (applY:foldl( a,[s(0),s(s(0))]),[a,a,a]). % было: ОШИБКА правда % сейчас нормально!
Пожалуйста, поделитесь своими идеями о том, как я мог / должен действовать!
(Я еще не проводил подобный эксперимент с другими процессорами Prolog.)
1 ответ
Это неотъемлемая особенность / ошибка модульных систем на основе предикатов в традиции Quintus. То есть эта модульная система была впервые разработана для Quintus Prolog. Впоследствии он был принят SICStus (после 0,7 1), затем (более или менее) 13211-2, затем YAP и (с некоторыми изменениями) SWI.
Проблема здесь в том, что именно означает явная квалификация. Пока цель не мета-предикат, вещи тривиально разрешимы: возьмите модуль самой внутренней квалификации. Однако, как только у вас есть мета-предикаты, мета-аргументы должны быть проинформированы об этом модуле; или нет. Если мета-аргументы проинформированы, мы говорим, что двоеточие устанавливает контекст вызова, если нет, то для этой цели нужны другие средства.
В традиции Квинта мета-аргументы принимаются во внимание. С результатом вы видите. Как следствие, вы не можете напрямую сравнивать две реализации одного и того же мета-предиката в одном и том же модуле. Существуют и другие подходы, особенно IF и ECLiPSe, которые не изменяют контекст вызова через двоеточие. Это имеет свои преимущества и недостатки. Лучше всего сравнить их в каждом конкретном случае.
Вот недавний случай. Возьмите лямбды и то, как они помещаются в модуль в SICStus, в SWI и в ECLiPSe.
Что касается модульной системы Quintus/SICStus/YAP/SWI, я бы предпочел использовать ее максимально консервативно. То есть:
нет явной квалификации, рассмотрим инфикс
:
как нечто внутреннеечистые, проверяемые мета-объявления - специально вставьте неопределенный предикат, чтобы посмотреть, способна ли перекрестная ссылка обнаружить проблему (в SWI это
check
или жеmake
).используйте общее подмножество, избегайте множества наворотов - есть много хороших расширений...
делать более универсальные вещи пешеходным способом: реэкспорт, добавив соответствующий модуль и добавить фиктивное определение. Точно так же, вместо переименования, импортируйте вещи из интерфейсного модуля.
всегда помните, что модульные системы имеют некоторые ограничения. Неважно, как вы крутите или поворачиваете его. Не существует полностью цельной модульной системы, поскольку самой целью модулей является разделение кода и задач.
1: Чтобы быть точным, адаптация модулей Quintus SICStus включала только :
для чувствительных к модулю аргументов в meta_predicate
деклараций. Целые числа 0..9
, которые так важны для программирования более высокого порядка на основе call/N
были введены только около 20 лет спустя в версии 4.2.0 2011-03-08.