Определение правила, которое пользователь не может запросить - PullRequest
1 голос
/ 25 февраля 2011

Как определить правило, которое пользователь не может запросить?Я хочу, чтобы сама программа вызывала это правило через другое правило.

Например:

rule1 (): - rule2 ().

rule2 (): - 1 <5. </p>

? - rule1 ().

true

? - rule2 ().

(я не знаю, каким будет ответЯ просто хочу, чтобы этот запрос не прошел!)

Ответы [ 3 ]

6 голосов
/ 25 февраля 2011

Используйте объект Logtalk для инкапсуляции ваших предикатов. Только предикаты, которые вы объявляете общедоступными, могут быть вызваны (вне объекта). Модули Prolog не препятствуют вызову каких-либо предикатов, так как при использовании квалификации explcit обходится список явно экспортированных предикатов.

Простой пример:

:- object(rules).

    :- public(rule1/1).
    rule1(X) :-
        rule2(X).

    rule2(X) :-
        X < 5.

:- end_object.

После компиляции и загрузки объекта выше:

?- rules::rule1(3).
true.

?- rules::rule2(3).
error(existence_error(predicate_declaration,rule2(3)),rules::rule2(3),user)

Если вы отредактируете объектный код и явно объявите rule2 / 1 как private, вы получите вместо этого ошибку:

?- rules::rule2(3).
error(permission_error(access,private_predicate,rule2(3)),rules::rule2(3),user)

Больше информации и множество примеров на http://logtalk.org/

2 голосов
/ 26 февраля 2011

Это напоминает мне объект, найденный в Java.Там можно запросить текущий стек вызовов и использовать его для регулирования разрешений вызова метода.В переводе на Пролог мы находим в старом Прологе DEC-10 следующий предикат:

предков (L)
Объединяет L со списком целей предков для текущего предложения.Список начинается с родительской цели и заканчивается самым последним предком, исходящим из вызова в скомпилированном предложении.Список печатается с использованием print, и каждой записи предшествует номер вызова в скобках, за которым следует номер глубины (как указано в сообщении трассировки).Если в вызове нет номера (это произойдет, если режим отладки не был включен до тех пор, пока не выполнится дальнейшее выполнение), это будет помечено знаком «-»Недоступно для скомпилированного кода.

Поскольку верхним уровнем обычно является скомпилированный предикат prolog / 0, его можно использовать для написания предиката, который проверяет свой собственный стек вызовов, а затем решает, хочет ли он перейти в службуили нет.

rule2 :- ancestors(L), length(L,N), N<2, !, write('Don't call me'), fail.
rule2 :- 1<5.

В современных Прологах мы уже не находим так часто предикат / 1.Но это можно смоделировать по следующим направлениям.Просто сгенерируйте ошибку, и в случае, если эта ошибка украшена трассировкой стека, вы получите все, что вам нужно:

ancestors(L) :- catch(sys_throw_error(ignore),error(ignore,L),true).

Но оптимизация удаления стека остерегается может уменьшить стек и, следовательно, список, возвращаемый предками /1.

С наилучшими пожеланиями

PS: Оптимизация удаления стека уже объяснена здесь: [4] Уоррен, DHD (1983): Набор абстрактных инструкций по прологу, Техническая записка 309, SRI International, октябрь, 1983

Дискуссия для Пржеке Джекике находится здесь: http://www.jekejeke.ch/idatab/doclet/prod/en/docs/10_pro08/13_press/03_bench/05_optimizations/03_stack.html

2 голосов
/ 25 февраля 2011

Во-первых, некоторые заметки:

  • Я думаю, что вы имеете в виду «предикат» вместо «правило». Предикат - это вещь name/k, такая как help/0help/1 - другое), и может иметь несколько предложений, среди которых факты и правила, например, length([], 0). (факт) и length([H|T], L) :- ... . (правило) - это два предложения одного предиката length/2.

  • Не используйте пустые скобки для предикатов без аргументов - по крайней мере, в SWI-Prolog это не будет работать вообще. Просто используйте predicate2 вместо predicate2() во всех местах.

  • Если вы попытаетесь вызвать неопределенный предикат, SWI-Prolog скажет
    ERROR: toplevel: Undefined procedure: predicate2/0 (DWIM could not correct goal), а Sicstus-Prolog скажет
    {EXISTENCE ERROR: predicate2: procedure user:predicate2/0 does not exist}

Теперь к ответу. Мне приходят в голову две идеи.

(1) Это взлом, но вы можете утверждать предикаты каждый раз, когда они вам нужны, и сразу же убирать их:

predicate1 :- 
      assert(predicate2), predicate2, retractall(predicate2).

Если вам нужны тело и аргументы для predicate2, введите assert(predicate2(argument1, argument2) :- (clause1, clause2, clause3)).

(2) Другим способом достижения этой цели было бы ввести дополнительный аргумент для предиката, который пользователь не хочет вызывать, и использовать его для идентификации, которую пользователь не может предоставить, но которую вы можете предоставить из вашего предиката призвания. Это может быть большое постоянное число, которое выглядит случайным, или даже предложение. Это даже позволяет вам выводить пользовательское сообщение об ошибке в случае неправильной идентификации.

* +1039 * Пример:
 predicate1 :- 
        predicate2("Identification: 2349860293587").

 predicate2(Identification) :- 
        Identification = "Identification: 2349860293587", 
        1 < 5.
 predicate2(Identification) :- Identification \= "Identification: 2349860293587",
        write("Error: this procedure cannot be called by the user. Use predicate1/0 instead."), 
        fail.

Я не использую эквивалент predicate2("Identification: 2349860293587") для первого предложения predicate2/0, потому что я не уверен, где заголовок предложения может появиться в сообщениях Пролога, а вы этого не хотите. Я использую fail в конце второго предложения только для того, чтобы Prolog печатал false вместо true после сообщения об ошибке. И, наконец, я понятия не имею, как запретить пользователю искать исходный код с помощью listing(predicate2), так что это по-прежнему позволит просто найти правильный идентификационный код, если он / она действительно этого хочет. Если это просто для предотвращения случайного вреда для пользователя, это должно быть достаточной защитой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...