Prolog-Аргументы недостаточно инстанцированы
Я пишу небольшую программу, которая подсчитывает количество элементов в списке не числились. Вот мой код:
not_number([],0).
not_number([X|T],R):-
not(number(X)),
R1 is R+1,
not_number(T,R1).
not_number([_|Tail],Result):-
not_number(Tail,Result).
если я выполняю такой код:
?- not_number([1,2,3,5], R).
я получаю, что r = 0 (как и должно быть)
R = 0.
но если я помещу символ в список:
?- not_number([1,2,3,5,a], R).
затем я получаю эту ошибку:
ERROR: not_number/2: Arguments are not sufficiently instantiated
Exception: (10) not_number([a], _G247) ?
может кто-то объяснит что не так с кодом? Я новичок в prolog.
3 ответов
Я пишу этот ответ, потому что лучший ответ был в комментарий by lurker. Я хочу, чтобы это было реальным ответом.
ваш код не работает, потому что вы делаете R1 is R+1
, когда R
не создается экземпляр в случае not_number([X|T], R)
. Ваш рекурсивный случай немного отстает. Вы хотите сделать это:
not_number([X|T],R):-
not(number(X)),
not_number(T,R1),
R is R1+1.
теперь правая сторона is
создается экземпляр при его вызове.
ваша проблема в том, что в арифметических вычислениях, как это:
A - Это B
все на правой стороне (B) должно быть уже известно. Никаких переменных.
вы можете сделать что-то вроде этого:
not_number(X, Y) :- not_number(X, Y, 0).
not_number([], Y, Y).
not_number([H|T], Y, Z) :-
\+ (number(H)),
Z1 is Z+1,
not_number(T, Y, Z1).
not_number([H|T], Y, Z) :-
number(H),
not_number(T, Y, Z).
(тестировал этот код, он работает).
теперь третий аргумент-аккумулятор. Он подсчитывает, сколько существует не-чисел. Когда список пуст, этот третий аргумент объединяется со вторым и становится правильным ответ.
Prolog, когда предоставляется возможность, будет проходить через все возможные маршруты. Если вы сделаете что-то вроде этого:
cat(adam).
cat(eve).
а потом спрашивают:
?- cat(X).
вы можете получить оба ответа: X = Адам и X = Ева. Это относится и к вашему коду: обратите внимание, что когда глава списка не является числом, вы все равно можете сделать это:
not_number([_|Tail],Result):-
not_number(Tail,Result).
который дает не тот ответ, который вы хотели бы. Вы должны отрезать маршруты, которые вас не интересуют. В данном случае я добавлю
number(Head).
чтобы убедиться, что мы пропускаем элемент в списке без увеличения счетчика на 1, только тогда, когда этот элемент не является числом.
чтобы применить Пролог, чтобы найти другие результаты, вы должны нажать "; " на клавиатуре (как в этом примере Адама и Евы).
общим решением таких проблем является использование ограничения.
например, ваша программа работает точно так, как ожидалось, если вы просто используете clpfd ограничения. Просто замените (is)/2
by (#=)/2
чтобы получить целочисленную арифметику, которая работает во всех направлениях:
:- use_module(library(clpfd)).
not_number([],0).
not_number([X|T],R):-
\+ number(X),
R1 #= R+1,
not_number(T,R1).
not_number([_|Tail],Result):-
not_number(Tail,Result).
Образец запроса и его результат:
?- not_number([1,2,3,5], R). R = 0.
Обратите также внимание, что я изменил код, чтобы использовать ISO-предикат (\+)/1
вместо not/1
.