Так что я подозреваю, что Фрэнк ищет ответ в Прологе, и да, он действительно пахнет домашнее задание ...
Ради интереса я решил написать свой ответ. Это заняло у меня около 50 строк.
Итак, вот схема того, как выглядят мои предикаты. Может быть, это поможет вам думать о прологе.
is_divisor(+Num,+Factor)
divisors(+Num,-Factors)
divisors(+Num,+N,-Factors)
sum(+List,-Total)
sum(+List,+Sofar,-Total)
is_perfect(+N)
perfect(+N,-List)
+ и - на самом деле не являются частью имен параметров. Это документальная подсказка о том, что автор ожидает создания экземпляра. (NB) «+ Foo» означает, что вы ожидаете, что Foo будет иметь значение при вызове предиката. «-Foo» означает, что вы ожидаете, что Foo будет переменной при вызове предиката, и дадите ему значение к моменту окончания. (вроде как ввод и вывод, если это помогает так думать)
Всякий раз, когда вы видите пару предикатов, таких как sum / 2 и sum / 3, шансы равны сумме / 2, которая похожа на оболочку для суммы / 3, которая делает что-то вроде аккумулятора .
Я не удосужился заставить его распечатывать их красиво. Вы можете просто запросить его непосредственно в командной строке Prolog:
?- perfect(100,L).
L = [28, 6] ;
fail.
Еще одна вещь, которая может оказаться полезной, которую я нахожу с предикатами Пролога, это то, что обычно есть два вида. Один - это тот, который просто проверяет, правда ли что-то. Для такого рода предикатов вы хотите, чтобы все остальное не сработало. Они не должны быть рекурсивными.
Другие захотят просмотреть диапазон (чисел или списка) и всегда возвращать результат, даже если он равен 0 или []. Для этих типов предикатов вам нужно использовать рекурсию и подумать о своем базовом случае.
НТН.
Примечание: это называется «режим», и вы можете указать их, и компилятор / интерпретатор будет применять их, но я лично использую их в документации. Также пытался найти страницу с информацией о режиме Пролог, но я не могу найти хорошую ссылку. (