2016-10-27 4 views
1

Я пишу предикат Пролога, который отсекает первые три элемента из пронумерованного списка и печатает результат. Пример нумерованного списка:Простая программа Пролог: ошибка «Аргументы недостаточно создаются»

[e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)]. 

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

strim([H|T],R) :- 
    append(P,R,[H|T]), 
    length(P,3). 

Таким образом, поскольку длина предикат отлично работает для нумерованных списков, а я только должен был написать предикат что добавляет один пронумерованный список к другому:

compose([],L,[L]). 
compose([e(F,C)|T],e(A,_),[e(F,C)|L]) :- 
    N is C+1, 
    compose(T,e(A,N),L). 

napp(X,[],X). 
napp(L,[e(X,Y)|T],M):- 
    compose(L,e(X,Y),L1), 
    napp(L1,T,M). 

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

numstrim([e(X,Y)|T],R) :- 
    napp(P,R,[e(X,Y)|T]), 
    length(P,3). 

Однако, я получаю эту ошибку:

ERROR: compose/3: Arguments are not sufficiently instantiated 

Может кто-нибудь объяснить, что вызывает ошибку и как ее избежать? Я новичок в Prolog.

+0

'N is C + 1' требует, чтобы' C' был создан, так как он пытается оценить 'C + 1'. – lurker

+0

@ lurker хорошо! извините, просить простой вопрос, как это, но как он будет выглядеть в моем коде? Я немного читал об экземплярах переменных, но я не вижу, что я могу сделать в этом случае конкретно ... – COLOuRSLIDES

+0

Ничего плохого в простом вопросе. :) Но у вас может быть больше домашней работы. «Инициировано» означает, что ему нужно связанное с ним значение. Поэтому, если 'C' не имеет значения, то Prolog не может evalutate' C + 1', и вы получите ошибку создания. Чтобы исправить это, вам нужно проверить свою логику и убедиться, что значение 'C' имеет значение. Вы вызываете 'compose (L, e (X, Y), L1)', и Prolog в конечном итоге попытается выполнить второе предложение для 'compose/3', которое соответствует' L' с '[e (F, C) | T]', без значения, связанного с 'C'. Таким образом, 'N является C + 1' терпит неудачу с ошибкой создания. – lurker

ответ

2

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

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

Например, в вашем случае, следующий тривиальным изменение compose/3 дает предикат, который работает во всех направлениях:

 
compose([], L, [L]). 
compose([e(F,C)|T], e(A,_), [e(F,C)|L]) :- 
     N #= C+1, 
     compose(T, e(A,N), L). 

Здесь, я просто заменил перебор режимов предикат (is)/2 с Ограничение CLP (FD)(#=)/2, которое completeley включает более низкоуровневый предикат над целыми числами.

После этого небольшого изменения (в зависимости от системы Prolog, возможно, придется импортировать библиотеку использовать более общие арифметические предикаты), получим:

 
?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es). 
nontermination 

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

Чтобы улучшить это, я теперь повернуть вокруг двух целей numstrim/2:

 
numstrim([e(X,Y)|T], R) :- 
     length(P, 3), 
     napp(P, R, [e(X,Y)|T]). 

Это потому, что length(P, 3)всегда заканчивается и размещая цель, которая всегда заканчивается первый может самое улучшить , никогда не ухудшаться, терминальные свойства чистой и монотонной логической программы.

Итак, теперь мы получаем:

 
?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es). 
Es = [e(b, _1442), e(a, _2678), e(r, _4286)] . 

То есть, по крайней мере, мы получаем ответ сейчас

Однако предикат еще не прекращаетуниверсально, потому что мы получаем:

 
?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es), false. 
nontermination 

Я оставляю фиксируя это в качестве упражнения.