Короткий ответ : он зацикливается, потому что plus(0, s(0), X).
произведет true
, а затем зациклится.
Если мы посмотрим на trace
мы видим:
[trace] ?- fib(s(s(s(0))), s(s(0))).
Call: (8) fib(s(s(s(0))), s(s(0))) ? creep
Call: (9) fib(s(s(0)), _902) ? creep
Call: (10) fib(s(0), _906) ? creep
Exit: (10) fib(s(0), s(0)) ? creep
Call: (10) fib(0, _910) ? creep
Exit: (10) fib(0, 0) ? creep
<b>Call: (10) plus(0, s(0), _912) ? creep</b>
...
Exit: (9) plus(s(0), s(0), s(s(0))) ? creep
Exit: (8) fib(s(s(s(0))), s(s(0))) ? creep
true .
Но интерпретатор возвращается к этому предикату и стремится найти больше решений.Это связано с тем, что ваш nat(Z)
каждый раз обнаруживает следующее значение, а затем интерпретатор вызывает plus(X, Y, Z)
, чтобы проверить, соответствует ли это значение, но каждый раз, когда оно терпит неудачу.
Мы можем видеть, чтокогда мы отследим plus(0, s(0), X)
:
[trace] ?- plus(0, s(0), X).
Call: (8) plus(0, s(0), _676) ? creep
Call: (9) nat(0) ? creep
Exit: (9) nat(0) ? creep
Call: (9) nat(0) ? creep
Exit: (9) nat(0) ? creep
Call: (9) nat(_884) ? creep
Exit: (9) nat(0) ? creep
Call: (9) plus(0, 0, 0) ? creep
Call: (10) nat(0) ? creep
Exit: (10) nat(0) ? creep
Exit: (9) plus(0, 0, 0) ? creep
Exit: (8) plus(0, s(0), s(0)) ? creep
X = s(0) ;
Redo: (9) plus(0, 0, 0) ? creep
Fail: (9) plus(0, 0, 0) ? creep
Redo: (9) nat(_884) ? creep
Call: (10) nat(_888) ? creep
Exit: (10) nat(0) ? creep
Exit: (9) nat(s(0)) ? creep
Call: (9) plus(0, 0, s(0)) ? creep
<b>Fail: (9) plus(0, 0, s(0)) ? creep</b>
Redo: (10) nat(_888) ? creep
Конечно, ни один из ответов, предложенных nat(Z)
, не будет выполнен, как только plus(0, s(0), X)
будет успешным.
Однако нет причины звонить nat(Z)
в любом случае, поскольку в конечном итоге рекурсивный вызов попадет в базовый регистр, который будет проверять nat(X)
, поэтому мы можем реализовать его следующим образом:
plus(X, 0, X) :- nat(X).
plus(X, s(Y), s(Z)) :- <b>plus(X, Y, Z)</b>.
Как правило, более эффективно использовать различные шаблоны в первый параметр:
plus(<b>0</b>, X, X) :- nat(X).
plus(<b>s(X)</b>, Y, s(Z)) :- <b>plus(X, Y, Z)</b>.