Разбиение большого целого числа с помощью Пролога

Я пытался научить себя Prolog в течение нескольких недель. Прямо сейчас я пытаюсь найти все способы сделать большое целое число из нескольких меньших целых чисел, используя предикат partition/3, который я хочу работать так:

| ?- partition(4, [1, 2, 3], X).

X = [1, 1, 1, 1] ? ;
X = [1, 1, 2] ? ;
X = [1, 3] ? ;
X = [2, 2] ? ;
no

таким образом найти все способы сделать 4 из 1, 2 и 3. Повторяющиеся решения, такие как [1, 2, 1] и [2, 1, 1], хороши, но, вероятно, их нетрудно избежать. Вот что у меня есть прямо сейчас:

partition(N, _, []) :- N = 0.
partition(N, [], _) :- fail.

partition(N, [IH|IT], [OH|OT]) :-
  N =< 0, fail;
  N > IH, M is N-IH, OH = IH,
  partition(M, [IH|IT], OT).
% if the first input IH can be subtracted from N,
% do so into M and push IH into the output list [OH|OT]

partition(N, [_|IT], Output) :-
  N =< 0, fail;
  partition(N, IT, Output). 
% after trying the first input term, try the others

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

| ?- partition(4, [1, 2, 3], X).

no

Первое и второе правила мне понятны, третье и четвертое кажутся сомнительными, но я не могу найти в них ничего особенно неправильного. Я думал, что выходной хвост OT может не быть создан, когда M станет равным нулю, но первое правило позаботится об этом. Или есть какое-то фундаментальное непонимание того, как работает Пролог (что, вероятно, часто случается со мной)?

Кроме того, части N =< 0, fail; избыточны? Они кажутся излишними, но я не могу быть уверен, пока не получу что-то работающее.

Изменить: я использую GNU Prolog.


person thko    schedule 11.02.2012    source источник


Ответы (1)


У вас есть одна проблема со сравнением N с IH:

partition(N, [IH|IT], [OH|OT]) :-
  N =< 0, fail;
  N > IH, [...]

Должно быть N >= IH.

Рассмотрим ваш пример partition(4, [1, 2, 3], X):

  1. Он соответствует предикату 3, который, в свою очередь, проверяет partition(3,[1,2,3],OT)
  2. partition(3,[1,2,3],OT) соответствует третьему предикату, проверяющему partition(2,[1,2,3],OT).
  3. partition(2,[1,2,3],OT) соответствует третьему предикату, проверяющему partition(1,[1,2,3],OT).
  4. partition(1,[1,2,3],OT) соответствует четвертому предикату, поскольку 1 > 1 терпит неудачу. Проверяет partition(1,[2,3],OT).
  5. partition(1,[2,3],OT) будет соответствовать четвертому предикату до конца и завершится ошибкой, если список пуст.
person Anders Lindahl    schedule 11.02.2012
comment
Замечательный! Спасибо, теперь это дает ожидаемый результат. - person thko; 11.02.2012
comment
@thko хорошие новости; если это так, то вы должны проголосовать и принять этот ответ. - person Will Ness; 05.09.2012