Пролог - Аргументы недостаточно проработаны

Я пишу небольшую программу, которая подсчитывает, сколько элементов в списке не являются числами. Вот мой код:

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) ? 

Может кто-нибудь объяснить, что не так с кодом? Я новичок в прологе.

3 ответа

Решение

Я пишу этот ответ, потому что лучшим ответом был комментарий 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 создается, когда он вызывается.

Ваша проблема в том, что в арифметических вычислениях это так:

А есть Б

все на правой стороне (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).

(протестировал этот код сейчас, он работает).

Теперь третий аргумент - это аккумулятор. Он подсчитывает, сколько существует не чисел. Когда список пуст, этот третий аргумент объединяется со вторым и становится правильным ответом.

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

cat(adam).
cat(eve).

а затем спросите:

?- cat(X).

Вы можете получить оба ответа: X = Адам и X = Ева. Это относится и к вашему коду: обратите внимание, что когда заголовок списка не является числом, вы все равно можете сделать это:

not_number([_|Tail],Result):-
    not_number(Tail,Result).  

который дает не тот ответ, который вы хотели бы. Вы должны отрезать маршруты, которые вас не интересуют. В этом случае я бы добавил

number(Head).

чтобы гарантировать, что мы пропускаем элемент в списке, не увеличивая счетчик на 1, только когда этот элемент не является числом.

Чтобы заставить Пролог найти другие результаты, вы должны нажать ";" на вашей клавиатуре (как в этом примере Адама и Евы).

Общее решение таких проблем заключается в использовании ограничений.

Например, ваша программа работает точно так, как ожидалось, если вы просто используете ограничения clpfd. Просто замени (is)/2 от (#=)/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,

В моем случае вместо is Мне пришлось использовать =

Вместо этого

X is AnotherVariable

Мне пришлось написать

X = AnotherVariable
Другие вопросы по тегам