Соответствующие кортежи в Прологе - PullRequest
1 голос
/ 24 мая 2010

Почему Prolog соответствует (X, Xs) кортежу, содержащему больше элементов? Пример:

test2((X, Xs)) :- write(X), nl, test2(Xs).                                    
test2((X)) :- write(X), nl.                                                   

test :-                                                                       
        read(W),                                                               
        test2(W). 

?- test.
|: a, b(c), d(e(f)), g.
a
b(c)
d(e(f))
g
yes

На самом деле это то, чего я хочу достичь, но это кажется подозрительным. Есть ли другой способ трактовать соединение терминов как список в Прологе?

Ответы [ 2 ]

2 голосов
/ 24 мая 2010
Конструкция

Tuple term с оператором ,/2 обычно ассоциируется справа в PROLOG (обычно называется sequence ), поэтому ваш ввод a, b(c), d(e(f)), g вполне может на самом деле быть термином (a, (b(c), (d(e(f)), g))). Об этом свидетельствует тот факт, что ваш предикат test2/1 напечатал то, что показано в вашем вопросе, где при первом вызове первого предложения test2/1, X соответствует a и Xs соответствует (b(c), (d(e(f)), g)), затем на втором вызове X соответствует b(c) и Xs соответствует (d(e(f)), g) и так далее.

Если вы действительно хотите иметь дело с списком терминов, интерпретируемых как соединение, вы могли бы использовать следующее:

test2([X|Xs]) :- write(X), nl, test2(Xs).                                    
test2([]).

... на входе [a, b(c), d(e(f)), g]. Структура списка здесь обычно интерпретируется немного иначе, чем для кортежей, созданных с помощью ,/2 (поскольку, по крайней мере, в SWI-PROLOG, такие структуры являются синтаксическим сахаром для работы с терминами, созданными с ./2, почти так же, как вы построить последовательности или кортежи с ,/2). Таким образом, вы получаете преимущества поддержки терминов списка, если вы можете разрешить интерпретацию терминов списка как соединения в вашем коде. Другой альтернативой является объявление и использование вашего собственного (возможно, инфиксного оператора) для соединения, такого как &/2, которое вы можете объявить как:

:- op(500, yfx, &). % conjunction constructor

Затем вы могли бы построить свой конъюнкт как a & b(c) & d(e(f)) & g и оттуда соответствующим образом разобраться с ним, точно зная, что вы подразумеваете под &/2 - союзом.

См. Страницу руководства для op/3 в SWI-PROLOG для получения более подробной информации - если вы не используете SWI, я предполагаю, что подобный предикат должен быть в любой реализации PROLOG, которую вы используете - - если оно того стоит, то соль: -)

РЕДАКТИРОВАТЬ: Чтобы преобразовать термин кортеж, построенный с использованием ,/2 в список, вы можете использовать что-то вроде следующего:

conjunct_to_list((A,B), L) :-
  !,
  conjunct_to_list(A, L0),
  conjunct_to_list(B, L1),
  append(L0, L1, L).
conjunct_to_list(A, [A]).
0 голосов
/ 24 мая 2010

Хмм ... a, b(c), d(e(f)), g означает a и (b(c) и (d(e(f)) и g)), а список [1,2,3] это просто [1 | [2 | [3 | []]]]. То есть если вы превратите эту конъюнкцию в список, вы получите тот же test2([X|Xs]):-..., но различие заключается в том, что конъюнкция несет информацию о том, как эти две цели объединены (также может быть дизъюнкция (X; Xs)). И вы можете построить другую иерархию союзов по (a, b(c)), (d(e(f)), g)

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

Возможно, вам следует использовать:

test2((X, Y)):- test2(X), nl, test2(Y).
test2((X; Y)). % TODO: handle disjunction
test2(X) :- write(X), nl.
...