Программирование на языке Пролог для искусственного интеллекта

       

Предикаты var nоnvar atom integer atomic



7. 1. 1.    Предикаты   var,  nоnvar,  atom,  integer,  atomic

Термы бывают разных типов: переменные, целые числа, атомы и т.д. Если терм - переменная, то в некоторый момент выполнения программы он может оказаться конкретизированным или не конкретизированным. Далее, если он конкретизирован, то его значение может быть атомом, структурой и т. п. Иногда бывает полезно узнать, каков тип этого значения. Например, пусть мы хотим сложить значения двух переменных Х и Y:

        Z  is  X + Y

Перед вычислением этой цели необходимо, чтобы Х и Y были конкретизированы целыми числами. Если у нас нет уверенности в том, что Х и Y действительно конкретизированы целыми числами, то перед выполнением арифметического действия нужно проверить это программно.

Для этого следует воспользоваться встроенным предикатом integer (целое). Предикат integer( X) принимает значение истина, если Х - целое или если Х - переменная, имеющая целое значение. Будем говорить в этом случае, что Х "обозначает" целое. Цель для сложения Х и Y можно тогда "защитить" такой проверкой переменных Х и Y:

        . . ., integer( X), integer( Y), Z is X + Y, . . .

Если неверно, что X и Y оба являются целыми, то система и не будет пытаться их сложить. Таким образом, цели integer "охраняют" цель Z is Х + Y от бессмысленного вычисления.

Встроенные предикаты этого типа таковы: var (переменная), nonvar (непеременная), atom (атом), integer (целое), atomic (атомарный). Они имеют следующий смысл:

        var( X)

Эта цель успешна, если Х в текущий момент - не конкретизированная переменная.

        nonvar( X)

Эта цель успешна, если Х - терм, отличный от переменной, или если Х - уже конкретизированная переменная.

        atom( X)

Эта цель истинна, если Х обозначает атом.

        integer( X)

Цель истинна, если Х обозначает целое.

        atomic( X)

Цель истинна, если Х обозначает целое или атом.

Следующие примеры вопросов к пролог-системе иллюстрируют применение этих встроенных предикатов:

        ?-  var( Z),  Z = 2.
        Z = 2

        ?-  Z = 2, var( Z).
        no

        ?-  integer( Z), Z = 2.
        no

        ?-  Z = 2, integer( Z), nonvar( Z).
        Z = 2

        ?-  atom( 22).
        no

        ?-  atomic( 22).
        yes

        ?-  atom( ==>).
        yes

        ?-  atom( p( 1) ).
        no

Необходимость в предикате atom продемонстрируем на следующем примере. Пусть мы хотим подсчитать, сколько раз заданный атом встречается в некоторой списке объектов. Для этого мы определим процедуру

        счетчик( А, L, N)

где А - атом, L - список и N - количество вхождений этого атома. В качестве первой попытки можно было бы определить счетчик так:

        счетчик( _, [ ], 0).

        счетчик( A, [A | L], N) :-  !,
                счетчик( A, L, N1),

                                    % N1 - число вхождений атома в хвост
                N is N1 + 1.

        счетчик( А, [ _ | L], N) :-
                счетчик( A, L, N).

Теперь на нескольких примерах посмотрим, как эта процедура работает:

        ?-  счетчик( а, [а, b, а, а], N).
        N = 3

        ?-  счетчик( a, [a, b, X, Y], Na).
        Na = 3
        . . .

        ?-  счетчик( b, [a, b, X, Y], Nb).
        Nb = 3
        . . .

        ?-  L=[a, b, Х, Y], счетчик( а, L, Na), счетчик( b, L, Nb).
        Na = 3
        Nb = 1
        X = a
        Y = a
        . . .

В последнем примере как X, так и Y после конкретизации получили значение а, и поэтому Nb оказалось равным только 1, однако мы хотели не этого. Нас интересовало количество реальных появлений конкретного атома, а вовсе не число термов, сопоставимых с этим атомом. В соответствии с этим более точным определением отношения счетчик мы должны теперь проверять, является ли голова списка атомом. Усовершенствованная программа выглядит так:

        счетчик( _, [ ], 0).

        счетчик( А, [В | L], N) :-
                atom( В), А = В,  !,                       % B равно атому А?
                счетчик( A, L, N1),                     % Подсчет в хвосте
                N is N1 + 1;
                счетчик( А, L, N).

                                % Иначе - подсчитать только в хвосте

В следующем более сложном упражнении по программированию числовых ребусов используется предикат nonvar.



Содержание раздела