Исходя из вопроса, я думаю, у вас неправильное представление о предикатах.Предикаты могут приводить только к true
или false
(ну, конечно, это может быть ошибка, или они могут зацикливаться вечно, если вы также рассматриваете их как "возможные результаты").Предикат может отвечать значениями , объединяя переменные, которые еще не зафиксированы.Как правило, в Прологе каждый предикат настолько универсален, насколько это возможно, так что можно назвать предикат разнонаправленный .
Вы называете предикат как:
FB is fact1(BB,R1),
Но fact1
не является функцией (функтор, для которого в предикате is/2
семантика известна).
Предикат может вычислять вещи и передавать результаты через объединение , например:
?- fac1(5, X).
X = 120 .
мы, таким образом, вызываем предикат fac1/2
с первым параметром, установленным в 5
, и Prolog объединит X
в 120
.
Мы можемпереписать предикат так:
main :- current_prolog_flag(argv,[BB_S,CC_S]),
atom_number(BB_S,BB),
atom_number(CC_S,CC),
fact1(BB, <b>FB</b>),
ABS is abs(BB - CC),
fact1(ABS, <b>FA</b>),
fact1(CC, <b>FC</b>),
Res is <b>FB</b> / (<b>FA</b> * <b>FC</b>),
write(Res).
Мы также можем сделать fac1
более декларативным: сейчас это работает только при фиксированном первом параметре (или в случае, если второй параметр 1
).Кроме того, это немного неэффективно, поскольку не использует оптимизацию хвостового вызова (TCO) .Мы можем улучшить предикат с помощью библиотеки clpfd
и реализовать ее следующим образом:
:- use_module(library(clpfd)).
fac(0, 1).
fac(I, F) :-
I #> 0,
F #= I*F1,
I1 #= I-1,
fac(I1, F1).
Теперь мы можем запрашивать факториальное отношение в нескольких направлениях:
?- fac(I, 120).
I = 5 ;
false.
?- fac(I, 130).
false.
?- fac(5, 120).
true ;
false.
?- fac(7, 120).
false.
?- fac(7, Y).
Y = 5040 ;
false.
Таким образом, мы можемзапрос, для которого i
, i!
равен 120
и т. д.
Мы также можем повысить производительность, внедрив продукт для определенного диапазона, поэтому:
b
------
| |
| | i
i=a+1
Таким образом, prodrange
, который в основном:
prodrange (A, B, P): - fac (A, FA), fac (B, FB), P - FB / FA.
но тогда более эффективно, так как это O (a + b) , и мы можем уменьшить его до O (b - a) , с:
prodrange(A, A, 1).
prodrange(A, B, P) :-
B > A,
B1 is B-1,
prodrange(A, B1, P1),
P is P1 * B1.
или более декларативный:
prodrange(A, A, 1).
prodrange(A, B, P) :-
B #> A,
P #= B*P1,
B1 #= B-1,
prodrange(A, B1, P1).
тогда мы можем реализовать предикат comb/3
для вычисления количества комбинаций:
comb(BB, CC, Res) :-
MX is max(BB, CC),
MN is min(BB, CC),
prodrange(MN, MX, Num),
Abs is MX-MN,
fac(Abs, Den),
Res is Num / Den.
тогда main
выглядит так:
main :-
current_prolog_flag(argv,[BB_S,CC_S]),
atom_number(BB_S,BB),
atom_number(CC_S,CC),
comb(BB, CC, BF),
print('Number of bracelets: '),
write(BF),
halt.