Эта программа имеет следующий недостаток: предикат len/2 можно использовать
только для подсчёта длины списка действительных чисел. Было бы неплохо, если бы
предикат len/2 мог принимать список любого типа. Это станет возможным, если вместо
домена real* подставить переменную типа. Однако, прежде чем проверять,
действительно ли эта схема работает, необходимо придумать для L=read() способ
извещения того, каким именно будет конечный тип вводимого списка, и передать эту
информацию в len/2. К счастью, существует предикат, который создаёт переменную
любого заданного типа. Ниже вы узнаете, как его использовать.
implement main /* В файле main.pro */
open core, console
class predicates
len : (Element*, real) procedure (i, o).
clauses
classInfo("avg", "1.0").
len([], 0) :- !.
len([_X|Xs], 1.0+S) :- len(Xs, S).
run():- console::init(),
hasDomain(real_list, L), L= read(),
len(L, A), write(A), nl.
end implement main
goal mainExe::run(main::run).
Следующим шагом в наших рассуждениях является добавление предложений для
предиката sum/2 в файл main.pro:
sum([], 0) :- !.
sum([X|Xs], S+X) :- sum(Xs, S).
Давайте посмотрим, что произойдёт, если вызвать sum([3.4, 5.6, 2.3], S).
1. Вызов sum([3.4, 5.6, 2.3], S)
соответствует предложению sum([X|Xs], S+X) :- sum(Xs, S), где X=3.4,
Xs=[5.6, 2.3],
возвращая sum([3.4, 5.6, 2.3], S[5.6, 2.3]+3.4) :- sum([5.6, 2.3],
S[5.6, 2.3])
2. Вызов sum([5.6, 2.3], S[5.6, 2.3])
соответствует предложению sum([X|Xs], S+X) :- sum(Xs, S), где X=5.6,
Xs=[2.3],
возвращая sum([5.6, 2.3], S[2.3]+5.6) :- sum([2.3], S[2.3])
3. Вызов sum([2.3], S[2.3])
соответствует предложению sum([X|Xs], S+X) :- sum(Xs, S), где X=2.3,
Xs=[],
возвращая sum([2.3], S[]+2.3) :- sum([], S[])
4. Вызов sum([], S
[]
), соответствует предложению sum([], 0.0) :- !, возвращая
S[]=0.
Достигнув конца списка, компьютер должен откатиться к началу вычислений. Что
еще хуже, он должен сохранить каждое значение переменной X, которое он найдет по
пути, чтобы произвести сложение S+X во время возвращения. Традиционный путь