Пролог: Почему этот предикат не завершается ошибкой с пустым списком, переданным в качестве аргумента

#prolog

Вопрос:

Я создал довольно простой предикат, чтобы объяснить свою проблему, так что не обращайте внимания на его бесполезность. Я хочу, чтобы предикат потерпел неудачу, если в качестве аргумента B передается пустой список,

 predicate(_,[],_) :- fail.
predicate(A,B,C) :- 
write(A),
writeln(B),
C = true.
 

Но когда я ввожу этот запрос:

?- predicate(test,[],X).

Вместо того, чтобы возвращать false(поскольку предполагается, что он завершится ошибкой), он выполняет предикат, и вывод будет:

 test[]
X = true.
 

Почему предикат не завершится ошибкой, даже если B-пустой список?

Ответ №1:

На самом деле, первое предложение не выполняется для запроса ?- predicate(test,[],X). . Однако, когда первое предложение завершается неудачно, второе предложение запускается и выдает наблюдаемый результат. Чтобы проверить это, вы можете использовать предикат trace/0 :

 ?- trace, predicate(test,[],X).
   Call: (11) predicate(test, [], _26304) ? creep  % <= try first clause
   Call: (12) fail ? creep
   Fail: (12) fail ? creep
   Redo: (11) predicate(test, [], _26304) ? creep  % <= try second clause
   Call: (12) write(test) ? creep
test
   Exit: (12) write(test) ? creep
   Call: (12) writeln([]) ? creep
[]
   Exit: (12) writeln([]) ? creep
   Call: (12) _26304=true ? creep
   Exit: (12) true=true ? creep
   Exit: (11) predicate(test, [], true) ? creep
X = true.
 

Если вы хотите, чтобы это predicate/3 не удалось при вызове со [] вторым аргументом, вы можете определить этот предикат следующим образом:

 predicate(A, B, C) :- 
    B = [],  % this condition forces failure when B is the empty list
    write(A), 
    writeln(B), 
    C = true.
 

Примеры:

 [trace]  ?- predicate(test,[],X).
   Call: (10) predicate(test, [], _28066) ? creep
   Call: (11) []=[] ? creep
   Fail: (11) []=[] ? creep
   Fail: (10) predicate(test, [], _28066) ? creep
false.

[trace]  ?- nodebug.
true.

?- predicate(test,[],X).
false.

?- predicate(test,[a],X).
test[a]
X = true.