Расширение цели для оператора `if_ / 3` в Прологе - PullRequest
3 голосов
/ 28 марта 2019

Я пишу токенизатор и хочу использовать if_/3 для сохранения в моем коде.

Код выглядит следующим образомкод 1 слева, но я хочу, чтобы он выглядел как справа.

if_(Cond1_1,                       %     (   Cond1_1
    Then1,                         %     *=> Then1
    if_(Cond2_1,                   %     ;   Cond2_1
        Then2,                     %     *=> Then2
        if_(Cond3_1,               %     ;   Cond3_1
            Then3,                 %     *=> Then3
            if_(Cond4_1,           %     ;   Cond4_1
                Then4,             %     *=> Then4
                if_(Cond5_1,       %     ;   Cond5_1
                    Then5,         %     *=> Then5
                    Else5          %     ;   Else5
   )   )   )   )   ).              %     ).

Чтобы переписать (*=>)/2 в if_/3 в SWI-PrologЯ придумал:

:- op(1050,xfy,*=>).

:- multifile goal_expansion/2.
goal_expansion((Cond *=> Then ; Else), if_(Cond,Then,Else)).
goal_expansion( Cond *=> Then        , (call(Cond,true), call(Then))).

" Готово ," Я думал ...

Но я стал сомневаться после прочтения документации SWI-Prolog дляgoal_expansion/2:

С помощью этого механизма раскрываются только цели, появляющиеся в теле предложений при чтении исходного файла, и только если они появляются буквально в предложении или в качестве аргумента дляопределенный мета-предикат, который аннотируется с использованием `0 '(см. meta_predicate / 1). В других случаях требуется настоящее определение предиката.

Итак, вот мой актуальный вопрос: Нужно ли мне также определение реального предиката?


Сноска 1 : фактический код имеет еще более длинную цепочку else if с.

1 Ответ

1 голос
/ 06 апреля 2019

Вам нужно определение предиката if_ / 3, чтобы хотя бы назначить ему объявление мета-предиката, иначе расширение остановится, если для самого if_ / 3 не будет объявления мета-предиката.

Вы можете попробовать самиЯ использую только это расширение:

:- op(1050,xfy,*=>).
:- multifile goal_expansion/2.
goal_expansion((Cond *=> Then ; Else), if_(Cond,Then,Else)).

Без объявления мета-предиката:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

?- expand_goal((a *=> b; c *=> d; e), X).
X = if_(a, b,  (c*=>d;e)).

С объявлением мета-предиката:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

:- meta_predicate if_(1,0,0).
?- expand_goal((a *=> b; c *=> d; e), X).
X = if_(a, b, if_(c, d, e)).

Это то же самое поведение вSWI-Пролог и Jekejeke Пролог.Вы можете изучить исходный код, чтобы лучше понять, зачем нужно объявление мета-предиката.

Смотрите, например, здесь:
https://github.com/jburse/jekejeke-devel/blob/master/jekrun/headless/jekpro/frequent/standard/expand.p#L220

...