Prolog — необычный синтаксис cons для списков

Я наткнулся на незнакомый фрагмент синтаксиса Пролога в статье Ли Нейша Программирование логики высшего порядка на Прологе.. Вот первый пример кода из статьи:

% insertion sort (simple version)
isort([], []).
isort(A.As, Bs) :-
    isort(As, Bs1),
    isort(A, Bs1, Bs).

% insert number into sorted list
insert(N, [], [N]).
insert(N, H.L, N.H.L) :-
    N =< H.
insert(N, H.LO, H.L) :-
    N > H,
    insert(N, LO, L).

Меня смущает A.As в isort(A.As, Bs) :-. Из контекста это кажется альтернативным синтаксисом cons для списков, эквивалентным isort([A|As], Bs) :-.

Кроме того, N.H.L кажется более удобным способом сказать [N|[H|L]].

Но SWI Prolog не примет этот необычный синтаксис (если только я не делаю что-то не так).

Кто-нибудь признает это? моя гипотеза верна? Какой интерпретатор Пролога принимает это как допустимый синтаксис?


person Nick Knowlson    schedule 05.04.2012    source источник
comment
Какой Пролог используется в статье?   -  person Chetter Hummin    schedule 05.04.2012
comment
Я просмотрел статью для этого, но, к сожалению, не смог найти там ссылку на него!   -  person Nick Knowlson    schedule 05.04.2012
comment
Это может быть просто синтаксический сахар   -  person Chetter Hummin    schedule 05.04.2012


Ответы (3)


Оператор точки использовался для списков в самой первой системе Prolog 1972 года, написанной на Algol-W, иногда называемом Prolog 0. Он вдохновлен аналогичными обозначениями в системах LISP. Следующий пример взят из статьи Алена Колмерауэра и Филиппа Рождение Пролога. Русселем, создателями Пролога.

+ELEMENT(*X, *X.*Y).
+ELEMENT(*X, *Y.*Z) -ELEMENT(*X, *Z).

В то время [] был NIL.

Следующая версия Пролога, написанная на Фортране Баттани и Мелони, использовала регистры для различения атомов и переменных. Затем DECsystem 10 Prolog представила нотацию квадратных скобок, заменив nil и X.Xs на [] и [X,..Xs], которые в более поздних версиях DECsystem 10 получили [X|Xs] в качестве альтернативы. В ISO Prolog есть только [X|Xs], .(X,Xs) и канонический синтаксис '.'(X,Xs).

Обратите внимание, что точка играет много разных ролей в ISO Prolog. Он служит уже как

  • конечный токен, за которым следует % или символ макета, такой как ПРОБЕЛ, НОВАЯ СТРОЧКА, TAB.

  • десятичная точка в числе с плавающей запятой, например 3.14159

  • графический токен char, формирующий графические токены как =..

Поэтому, если вы теперь объявляете . в качестве инфиксного оператора, вы должны быть очень осторожны. Как с тем, что вы пишете, так и с тем, что будут читать системы Prolog. Один дополнительный пробел может изменить значение термина. Рассмотрим два списка чисел в обеих нотациях:

[1,2.3,4]. [5].
1 .2.3.4.[]. 5.[].

Обратите внимание, что вы должны добавить пробел после 1. В этом контексте дополнительный пробел перед числом может изменить значение ваших терминов. Вот так:

[1|2.3]. [4]. 5. [].
1 .2.3. 4.[]. 5. [].

Вот еще один пример, который может быть еще более убедительным:

[1,-2].
1.(-2).[].

Отрицательные числа требуют круглых скобок в точечных списках.

Сегодня остались только YAP и XSB, которые по-прежнему предлагают инфикс . по умолчанию, и они это делают. иначе. И XSB даже не распознает приведенный выше синтаксис с точкой: вам нужны круглые скобки вокруг некоторых неотрицательных чисел.

Вы написали, что N.H.L кажется более удобным способом сказать [N|[H|L]]. Существует простое эмпирическое правило для упрощения таких выражений в ISO Prolog: всякий раз, когда вы видите в списке токены | и [ сразу друг за другом, вы можете заменить их на , (и удалить соответствующий ] с правой стороны) . Итак, теперь вы можете написать: [N,H|L] что не выглядит так уж плохо.

Вы можете использовать это правило и в другом направлении. Если у нас есть список [1,2,3,4,5], мы можем использовать | как "лезвие бритвы", например: [1,2,3|[4,5]].


Еще одно замечание, поскольку вы читаете статью Нейша: тем временем, она хорошо понята что нужно только call/N! И ISO Prolog поддерживает call/1, call/2 до call/8.

person false    schedule 05.04.2012
comment
Вау, какой развернутый ответ, спасибо большое! [N,H|L] действительно намного приятнее, я понятия не имел, что это действительно так. Я также ценю указатель на этот обмен, это действительно интересно. - person Nick Knowlson; 05.04.2012
comment
Вам может быть интересно узнать, как лямбда-выражения сочетаются с call/N. - person false; 06.04.2012
comment
я только что проверил, и пунктирная пара появляется в первой статье Маккарти по lisp - cs.unm.edu/~luger/cs451/resources/recursive.pdf (раздел 3) - person andrew cooke; 16.04.2012
comment
@andrew cooke: В статье используется не только точка, но и запятая — на стр. 9 есть показательная сноска №3. - person false; 16.04.2012
comment
@false знаете ли вы о правиле 10 правок? вы рискуете превратить этот ответ в вики-сообщество, так что у вас больше не будет репутации в будущем и вообще никакой репутации для вашего тега. Просто чтобы вы знали. :) - person Will Ness; 24.09.2012
comment
@Уилл Несс: Спасибо. Нет, я не знаю об этом правиле (я всегда надеюсь найти хорошего юриста SO...). Немного жаль: в ответе должны быть еще некоторые подробности, чтобы понять точный синтаксис -1. - person false; 24.09.2012
comment
ах, хорошо, что я сказал вам тогда. :) У вас есть два варианта (но я не юрист): добавить еще один ответ или после внесения еще одного редактирования пометить ваш ответ и попросить модератора удалить его из вики-сообщества. Но это крайнее средство (я сделал это однажды по тем же причинам). Или вы можете спросить об этом на мета. :) - person Will Ness; 24.09.2012

Да, вы правы, точка - это инфиксный оператор списка cons. На самом деле это требуется стандартом ISO Prolog, но обычно скрыто. Я нашел (и использовал) этот синтаксис некоторое время назад:

:- module(eog, []).
:- op(103, xfy, (.)).

% where $ARGS appears as argument, replace the call ($ARGS) with a VAR
% the calle goes before caller, binding the VAR (added as last ARG)
funcs(X, (V, Y)) :-
    nonvar(X),
    X =.. W.As,

    % identify meta arguments
    (   predicate_property(X, meta_predicate M)
        % explicitly exclude to handle test(dcg)
        % I'd like to handle this case in general way...
    ,   M \= phrase(2, ?, ?)
    ->  M =.. W.Ms
    ;   true
    ),

    seek_call(As, Ms, Bs, V),
    Y =.. W.Bs.

% look for first $ usage
seek_call([], [], _Bs, _V) :-
    !, fail.
seek_call(A.As, M.Ms, A.Bs, V) :-
    M @>= 0, M @=< 9, % skip meta arguments
    !, seek_call(As, Ms, Bs, V).
seek_call(A.As, _, B.As, V) :-
    nonvar(A),
    A = $(F),
    F =.. Fp.FAs,
    (   current_arithmetic_function(F) % inline arith
    ->  V = (PH is F)
    ;   append(FAs, [PH], FBs),
        V =.. Fp.FBs
    ),
    !, B = PH.
seek_call(A.As, _.Ms, B.As, V) :-
    nonvar(A),
    A =.. F.FAs,
    seek_call(FAs, Ms, FBs, V),
    !, B =.. F.FBs.
seek_call(A.As, _.Ms, A.Bs, V) :-
    !, seek_call(As, Ms, Bs, V).

:- multifile user:goal_expansion/2.
user:goal_expansion(X, Y) :-
    ( X = (_ , _) ; X = (_ ; _) ; X = (_ -> _) )
    -> !, fail % leave control flow unchanged (useless after the meta... handling?)
    ;  funcs(X, Y).

/* end eog.pl */

Мне посоветовали против этого. По сути, синтаксис [A|B] — это эволюция синтаксиса . оператор, введенный для удобства чтения.

OT: что это за код?

приведенный выше код — моя попытка подсластить Пролог функциями. А именно, вводит по запросу посредством $ временные переменные, необходимые (например) арифметическими выражениями

fact(N, F) :-
     N > 1 -> F is N * $fact($(N - 1)) ; F is 1.

каждый $ представляет переменную. После расширения у нас есть более традиционный факт/2

?- listing(fact).
plunit_eog:fact(A, C) :-
    (   A>1
    ->  B is A+ -1,
        fact(B, D),
        C is A*D
    ;   C is 1
    ).

Там, где у нас много выражений, это может быть полезно...

person CapelliC    schedule 05.04.2012
comment
Большое спасибо за ответ! Я не понимаю, как работает $, но в примере с $fact это очень убедительно - мне придется потратить некоторое время на изучение этого кода. - person Nick Knowlson; 06.04.2012
comment
Чтобы протестировать этот код, ваш Пролог должен предоставить target_expansion/2 и модули. Оба являются расширениями де-факто, не одобренными ISO. Простите за это. По сути, ISO Prolog — это очень ограниченный язык доступных реализаций WRT, это одна из основных проблем Prolog... - person CapelliC; 06.04.2012
comment
@chac: системы по-прежнему меняют свое значение goal_expansion/2 и т.п. от выпуска к выпуску. Это практически невозможно стандартизировать. - person false; 16.04.2012
comment
@false: его тоже не очень легко использовать. SWI-Prolog легко блокируется при перекомпиляции предварительного кода или, что еще лучше, генерирует большое количество сообщений о переопределении и входит в своего рода цикл перекомпиляции (я думаю). К счастью, недавний пост Яна в списке SWI-Prolog прояснил вопрос. - person CapelliC; 16.04.2012
comment
@chac: смысл по-прежнему отличается между SWI и SICStus. Было бы уже здорово, если бы системы соответствовали существующему стандарту. Прогресс есть, но его может быть гораздо больше . - person false; 16.04.2012

Этот синтаксис взят из NU-Prolog. См. здесь. Вероятно, это просто обычный функтор списка '.'/2, переопределенный как инфиксный оператор, без необходимости завершающего пустого списка:

?- L= .(a,.(b,[])).
L = [a,b]
Yes (0.00s cpu)
?- op(500, xfy, '.').
Yes (0.00s cpu)
?- L = a.b.[].
L = [a,b]
Yes (0.00s cpu)
person twinterer    schedule 05.04.2012
comment
Синтаксис намного старше, чем у NU (1987) или MU. - person false; 05.04.2012
comment
@false: мне любопытно. Можете ли вы указать на какие-либо ссылки, которые легко доступны? Я никогда не видел, чтобы он использовался как инфиксный оператор где-либо еще. Например, не помню, чтобы видел это в C&M. - person twinterer; 05.04.2012
comment
Я добавил наиболее заметную ссылку на свой ответ. - person false; 05.04.2012