Пролог: деление числа

Я хотел сделать предикат, который возвращает список делителей числа. Пример: 72 = 2*2*2*3*3.

prdel(A,[],_):- 
      A is 1.
prdel(P,[D|L],D):-
      0 is mod(P,D),
      P1 is P/D,
      prdel(P1,L,D).
prdel(P,L,D):-
      D1 is D+1,
      prdel(P,L,D1).

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

Я пытался отредактировать последний как этот,

prdel(P,L,D):-
      D1 is D+1,
      D1<P,
      prdel(P,L,D1).

но теперь он возвращает только ложь, а не список.

РЕДАКТИРОВАТЬ:

Я ищу ответ без разреза.

1 ответ

Решение

Одна проблема в вашем коде состоит в том, что он пытается разделить число P от D даже когда ясно, что разделение не будет успешным, потому что D слишком высоко Это позволяет D "убежать" без ограничений.

Добавление чека для D1 быть ниже или равно P исправляет эту проблему:

prdel(1,[],_).

prdel(P,[D|L],D):-
      0 is mod(P,D),
      P1 is P/D,
      prdel(P1,L,D).

prdel(P,L,D):-
      D1 is D+1,
      D1 =< P,
      prdel(P,L,D1).

Это создает все комбинации делителей, включая не простые ( демо).

[[2, 2, 2, 3, 3], [2, 2, 2, 9], [2, 2, 3, 6],
 [2, 2, 18], [2, 3, 3, 4], [2, 3, 12], [2, 4, 9],
 [2, 6, 6], [2, 36], [3, 3, 8], [3, 4, 6], [3, 24],
 [4, 18], [6, 12], [8, 9], [72]]

Если вы этого не хотите, добавьте условие mod(P,D) > 0 в последнем пункте:

prdel(1,[],_).

prdel(P,[D|L],D):-
    0 is mod(P,D),
    P1 is P/D,
    prdel(P1,L,D).

prdel(P,L,D):-
    mod(P,D) > 0,
    D1 is D+1,
    D1 =< P,
    prdel(P,L,D1).

Это производит только [2, 2, 2, 3, 3] ( демо).

Другие вопросы по тегам