#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.