Что означают числовые c аргументы для meta_predicate в SWI-Prolog? - PullRequest
2 голосов
/ 29 марта 2020

Я пишу программу Prolog и пытаюсь внедрить модули в дизайн программы для инкапсуляции сложности и уменьшения избыточности.

Одна из проблем, с которыми я сталкиваюсь, - это использование метапредикатов. Я хотел бы определить метапредикат в одном модуле, а затем импортировать его в другой модуль; это вводит осложнения. К счастью, директива meta_predicate помогает разрешать префиксы модулей, но у меня возникают проблемы с пониманием аргументов, как описано здесь: https://www.swi-prolog.org/pldoc/man?section=metapred

В частности, у меня проблемы с цифрой c аргументы. Согласно документации:

Аргумент - это термин, который используется для ссылки на предикат с N аргументами больше, чем у данного аргумента. Например: call (0) или maplist (1, +).

Я понимаю, что аргумент, обозначенный значением цифра c, будет термином, который используется для ссылки на предикат. Я не понимаю, как указанный предикат может иметь больше аргументов, чем термин аргумента. Может ли кто-нибудь предложить более глубокое объяснение того, когда аргумент числовой c уместен, или пример того, когда было бы целесообразно использовать его?

Ответы [ 2 ]

3 голосов
/ 29 марта 2020

Это формулировка, которую легко понять, только когда известно, что это значит, и, вероятно, ее следует переделать.

:-meta_predicate maplist(2, ?, ?).

... просто означает, что аргумент на месте "2 будет использоваться в качестве ядра предиката, который будет вызываться. У нас нет специальных обозначений для этого (большая ошибка, ИМХО), поэтому мы напишем это стандартным образом как термин типа f(foo,bar), или f(foo), или f. Что мета-предикат maplist/3 будет делать с этим термином? Что ж, он синтаксически преобразует его и добавит «2» дополнительных аргументов на своем конце (и только на своем конце, что приводит к неловкости): f(foo,bar, ARG1,ARG2), или f(foo, ARG1,ARG2), или f(ARG1,ARG2). Тогда maplist/3 вызовет его.

Например, для вышеупомянутого maplist/3, возьмите этот предикат, принимая два аргумента:

myprint(X,Y) 
   :- format("~w\n",[(X,Y)]).

Может использоваться в таком вызове maplist/3 без указания каких-либо аргументов:

maplist(myprint,[0,1,2,3],[a,b,c,d]).

и два аргумента, по одному из каждого списка, будут добавлены в термин myprint, прежде чем этот термин будет посвящен в рыцари, чтобы стать предикатом и называется:

?- maplist(myprint,[0,1,2,3],[a,b,c,d]).
0,a
1,b
2,c
3,d
true.

Это позволяет пропускать «частично заполненные вызовы». maplist/2 прикрепит 1 аргумент к концу своего первого аргумента, поэтому можно сказать:

?- maplist(myprint("foo+"),[a,b,c,d]).
foo+,a
foo+,b
foo+,c
foo+,d
true.

Вышеприведенное становится фактически пригодным для использования в сочетании с library(yall) Пауло Моуры, который оборачивает цель в анонимный предикат, выставляя аргументы. Тогда можно гибко переставить вещи

?- maplist([X,Y]>>format("~w\n",[(X,Y)]),[0,1,2,3],[a,b,c,d]).
0,a
1,b
2,c
3,d
true.
?- maplist([Y,X]>>format("~w\n",[(X,Y)]),[0,1,2,3],[a,b,c,d]).
a,0
b,1
c,2
d,3
true.

Фактически library(yall) обеспечивает правильный синтаксис для лямбда-выражений, который безжалостно отсутствует в стандарте ISO, чтобы явно показывать отсутствующие параметры.

Кто-то мог представить себе такие длинные выражения go:

?- maplist(λX.verify(3,X), [1,2,3,4,5]).

или остаться в ASCIIland, что-то вроде:

?- maplist(\X.verify(3,X), [1,2,3,4,5]).

, но это не случилось.

2 голосов
/ 29 марта 2020

Директива мета-предиката указывает количество аргументов, которые нужно добавить к предикату при вызове. Вот простой пример:

:- meta_predicate foo(2, +).

foo(Pred, X) :-
    call(Pred, X, Y),
    format('~q(~q,~q)~n', [Pred, X, Y]).

some_pred(X, Y) :-
    Y is X + 1.

, который дает следующий результат. Как видите, директива meta_predicate приводит к аргументу Pred, добавляющему модуль (в данном случае user):

?- foo(some_pred, 5).
user:some_pred(5,6)

Что-то похожее на "замыкание" в других языки могут быть легко сделаны, также используя директиву meta_predicate. Например, мы могли бы иметь

:-meta_predicate foo2(1). 

foo2(Pred):-
    call(Pred, Y),
    format('~q=~q',[Pred,Y]).

и назвать его:

?-foo2(some_pred(5)).
...