Шаг 7.
Простейшие компараторы

    На этом шаге мы введем понятие функций-компараторов.

    Функции-компараторы - это функции, используемые для сравнения обьектов данных muLISP. Все они требуют двух или более аргументов и, за исключением функции MEMBER, возвращают значение Т или NIL, т.е. являются предикатами.

    Приведем список этих функций.

Таблица 1. Простейшие компараторы muLISP81
Функция
Назначение
EQ
Проверяет, находятся ли объекты в одной и той же области памяти.
EQUAL
Ппроверяет тождественность двух S-выражений.
MEMBER
Проверяет, входит ли данный объект в список.
LESSP
Проверяет, какой из числовых аргументов меньше.
GREATERP
Проверяет, какой из числовых аргументов больше.
ORDERP
Проверяет порядок следования аргументов.

    1. Функция EQ. Предикат EQ определяет, представлены ли два объекта языка LISP в памяти компьютера физически одной и той же структурой, т.е. находятся ли в одном и том же месте памяти. Например:


   $ (EQ 5 5)     $ (EQ A A)
   T              T

    Так как EQ определен лишь для атомов, то для сравнения двух выражений, прежде всего надо определить, являются ли они атомами. Если хотя бы один из аргументов является списком, то предикат EQ нельзя использовать для логического сравнения. Например:


   $ (EQ (1 2 3) (1 2 3))
   NIL


В начало таблицы

    2. Функция EQUAL. Предикат EQUAL проверяет тождественность двух S-выражений (их логическую эквививалентность). Например:


   $ (EQUAL (1 2 3) (1 2 3))
   T

    Предикат EQUAL является обобщением функции EQ: он применяется к произвольным списковым структурам. Используйте его в тех случаях, когда нет уверенности в типе сравниваемых объектов или в корректности использования предиката EQ.

В начало таблицы

    3. Функция MEMBER. Синтаксис функции таков:


              (MEMBER OBJECT LIST)

    Предикат MEMBER проверяет, входит ли данный объект OBJECT в список LIST. При этом недостаточно, чтобы первый аргумент был где-то "похоронен" во втором аргументе: требуется, чтобы это был элемент верхнего уровня второго аргумента. Например:


   $ (MEMBER A ((A B) (C D)))
   NIL

    Заметим, что функции EQ, EQUAL, MEMBER иногда называют примитивными функциями сопоставления с образцом.

В начало таблицы

    4. Функция LESSP. Предикат LESSP проверяет для числовых аргументов какой из них меньше.

В начало таблицы

    5. Функция GREATERP. Предикат GREATERP проверяет для числовых аргументов какой из них больше.

В начало таблицы

    6. Функция ORDERP. Предикат ORDERP имеет два аргумента (оба могут быть либо атомами, либо числами, либо точечными парами). Предикат возвращает T, если первый аргумент "располагается перед" вторым аргументом, иначе функция возвращает NIL.

    При этом учтите, что числа "располагаются перед" атомами; они в свою очередь располагаются перед точечными парами. Два числа располагаются в порядке возрастания. Два атома "располагаются" согласно результату сравнения их адресов в физической памяти (т.е. согласно порядку их ввода). Аналогично располагаются и две точечные пары. Например:


   $ (ORDERP 5 9)     $ (ORDERP DOG CAT)
   T                  T
   $ (ORDERP DOG 5)   $ (ORDERP CAT DOG)
   NIL                NIL

    Функция ORDERP обеспечивает оптимальное "хронологическое" расположение атомов при написании программ сортировки.

В начало таблицы

   

    В версии muLISP85 существуют еще несколько функций-компараторов: EQL, MEMBER-IF, =, /=, <, >, <=, >=, MISMATCH. Остановимся на них более подробно.

Таблица 2. Простейшие распознаватели muLISP85
Функция
Назначение
EQ
Проверка на идентичность двух объектов.
EQL
Проверка на идентичность двух объектов.
EQUAL
Проверка на идентичность двух объектов.
MEMBER
Поиск элемента в списке.
(= N1 N2 ... Nm)
Попарная проверка на равенство аргументов.
(/= N1 N2 ... Nm)
Попарная проверка на неравенство аргументов.
(< N1 N2 ... Nm)
Попарная проверка на возрастание аргументов.
(> N1 N2 ... Nm)
Попарная проверка на убывание аргументов.
(<= N1 N2 ... Nm)
Попарная проверка на невозрастание аргументов.
(>= N1 N2 ... Nm)
Попарная проверка на неубывание аргументов.
MISMATCH
Сравнение элементов списка.

    1. Если OBJECT1 идентичен OBJECT2, то функция (EQ OBJECT1 OBJECT2) возвращает Т, иначе - NIL.

    Функция (NEQ OBJECT1 OBJECT2) эквивалентна функции (NOT (EQ OBJECT1 OBJECT2)).

    Функция EQ проверяет на идентичность два своих аргумента (указывают ли она на одинаковых обьекта данных в памяти). Т.к. символы и малые целые числа (т.е. целые числа, меньше 65536 по абсолютной величине) определяются уникально, то функция EQ является хорошим способом определения, являются ли два символа или два малых целых числа равными друг другу. Например:


   $ (EQ 'Alice 'Alice)   $ (EQ FOO BAR)
   T                      T
   $ (SETQ FOO '(A B C))  $ (EQ 7 (+ 3 4))
   (A B C)                T
   $ (EQ FOO '(A B C))    $ (EQ 100000 100000)
   NIL                    NIL
   $ (SETQ BAR FOO)
   (A B C)
Приведем код функции:

   (DEFUN EQ (OBJ1 OBJ2)
      (= (LOCATION OBJ1) (LOCATION OBJ2))
   )
В начало таблицы

    2. Если OBJECT1 идентичен OBJECT2 или если оба аргумента являются числами с одинаковыми значениями, то функция (EQL OBJECT1 OBJECT2) возвращает Т, иначе - NIL.

    Функция (NEQL OBJECT1 OBJECT2) эквивалентна функции (NOT (EQL OBJECT1 OBJECT2)).

    Т.к. большие целые числа (целые числа, большие 65536 по абсолютной величине) и дробные числа не определяются уникально, то функция EQL по сравнению с функцией EQ может быть гораздо эффективнее при определении эквивалентности двух чисел. Аргументы-неатомы являются эквивалентными тогда и только тогда, когда они указывают на одинаковые точечные пары в памяти. Например:


   $ (EQL 'Alice 'Alice)   $ (EQL 100000 100000)
   T                       T
   $ (EQL 7 (+ 3 4))       $ (EQL '(A B) '(A B))
   T                       NIL
Приведем код функции:

   (DEFUN EQL (OBJ1 OBJ2)
      ( (AND (NUMBERP OBJ1) (NUMBERP OBJ2))
          (= OBJ1 OBJ2) )
      (= (LOCATION OBJ1) (LOCATION OBJ2))
   )
В начало таблицы

    3. Если OBJECT1 эквивалентен OBJECT2, то функция (EQUAL OBJECT1 OBJECT2) возвращает Т, иначе - NIL. Функция EQUAL проверяет на эквивалентность два своих аргумента.

    Если один или оба аргумента являются атомами, то функция EQUAL действует аналогично функции EQL.

    Два аргумента-неатома находятся в отношении EQUAL, если они являются изоморфными структурами данных: и CAR-ветви, и CDR-ветви есть EQUAL. Две EQUAL-структуры данных при печати изображаются одинаково. Т.к. EQL работает быстрее, эту функцию лучше использовать вместо EQUAL там, где известно, что по крайней мере один из аргументов является атомом. Например:


   $ (EQUAL 'A 'A)
   T
   $ (EQUAL '(A B C) '(A B C))
   T
   $ (EQUAL '(A B C) '(C B A))
   NIL
Приведем код функции:

   (DEFUN EQUAL (OBJ1 OBJ2)
      ( (ATOM OBJ1) (EQL OBJ1 OBJ2) )
      ( (ATOM OBJ2) NIL )
      ( (EQUAL (CAR OBJ1) (CDR OBJ2))
           (EQUAL (CDR OBJ1) (CDR OBJ2)) )
   )
В начало таблицы

    4. Функция (MEMBER OBJECT LIST TEST) выполняет линейный поиск в LIST элемента, для которого признак сравнения с OBJECT по тесту TEST не равен NIL. Если TEST-аргумент есть NIL или не задан, то функция MEMBER использует EQL-тест.

    Функция (MEMBER-IF TEST LIST) выполняет поиск в списке LIST элемента, для которого признак проверки по тесту TEST есть не NIL. Для обеих функций, если элемент, удовлетворяющий тесту TEST, найден, выдается хвост списка LIST, начиная с данного элемента. Иначе возвращается NIL. Например:


   $ (MEMBER 'A '(B C D))
   NIL
   $ (MEMBER 'A '(B A D))
   (A D)
   $ (MEMBER-IF 'NUMBERP '(A B 3 C (-7)))
   (3 C (-7))
   $ (MEMBER-IF 'MINUSP '(A B 3 C (-7)))
   NIL
Код функции таков:

   (DEFUN MEMBER (OBJ LST TEST)
      ( (ATOM LST) NIL)
      ( ( (NULL TEST) (SETQ TEST 'EQL) )
        ( (FUNCALL TEST OBJ (CAR LST)) LST )
      (MEMBER OBJ (CDR LST) TEST)
   )
В начало таблицы

    5. Если N1 равно N2, N2 равно N3,..., Nm-1 равно Nm, то функция (= N1 N2 ... Nm) возвращает Т, иначе - NIL. Функция вызывает прерывание "Нечисловой аргумент", если какой-либо аргумент не является числом. Например:


   $ (= 5 9)       $ (= 3 3.0)
   NIL             T
   $ (= 4 4 -7)    $ (= 0.75 6/8)
   NIL             T
В начало таблицы

    6. Если N1 не равно N2, N2 не равно N3,...,Nm-1 не равно Nm, то функция (/= N1 N2 ... Nm) возвращает Т, иначе - NIL. Например:


   $ (/= 5 9)      $ (/= 3 3.0)
   T               NIL
   $ (/= 4 4 -7)   $ (/= 0.75 6/8)
   NIL             NIL

    Отметим, что если функция возвращает Т, то это означает, что нет ни одной пары смежных равных аргументов. Однако это может быть и в том случае, когда два аргумента равны, но не являются смежными. Например:


   $ (/= 6 -2 6)
   T

    Если какой-либо аргумент не является числом, возникает прерывание по ошибке "Нечисловой аргумент".

    Приведем реализацию функции:


   (DEFUN /= LST
      ( (NULL LST) )
      ( (NULL (CDR LST)) )
      ( (AND (NUMBER (CAR LST)) (NUMBER (CADR LST)))
           ((= (CAR LST) (CADR LST)) NIL)
           (APPLY '/= (CDR LST)) )
      ((BREAK (LIST '/= (CAR LST) (CADR LST))
              'Nonnumeric Argument") NIL)
      (APPLY '/= (CDR LST))
   )
В начало таблицы

    7. Если N1<N2, N2<N3,..., Nm-1<Nm, то функция (< N1 N2 ... Nm) возвращает Т, иначе - NIL. Например:


   $ (< 5 9)     $ (< 3 3.0)
   T             NIL
   $ (< 4 -7)    $ (< 3/5 2/3)
   NIL           T

    Если какой-либо аргумент не является числом, то возникает прерывание по ошибке "Нечисловой аргумент".

    Функцию удобно использовать в том случае, когда нужно определить, лежит ли число внутри данного интервала; при этом она вызывается с тремя аргументами: числом и границами интервала. Например, ниже показано, как определить, является ли значение CHAR:


 числом:                  (< 47 (ASCII CHAR) 58)
 прописной буквой:        (< 64 (ASCII CHAR) 91)
 строчной буквой:         (< 96 (ASCII CHAR) 123)
В начало таблицы

    8. Если N1>N2, N2>N3,..., Nm-1>Nm, то функция (gt N1 N2 ... Nm) возвращает Т, иначе - NIL. Например:


   Например:
   $ (> 5 9)     $ (> 3 3.0)
   NIL           NIL
   $ (> 4 -7)    $ (> 3/5 2/3)
   T             NIL

    Если какой-либо аргумент не является числом, то возникает прерывание по ошибке "Нечисловой аргумент".

В начало таблицы

    9. Если N1<=N2, N2<=N3,..., Nm-1<=Nm, то функция (<= N1 N2 ... Nm) возвращает Т, иначе - NIL. Например:


   $ (<= 5 9)    $ (<= 3 3.0)
   T             T
   $ (<= 4 -7)   $ (<= 3/5 2/3)
   NIL           T

    Если какой-либо аргумент не является числом, то возникает прерывание по ошибке "Нечисловой аргумент".

    Приведем код функции:


   (DEFUN <= LST
      ((NULL LST))
      ((NULL (CDR LST)))
      ((AND (NUMBERP (CAR LST)) (NUMBERP (CADR LST)))
          ((> (CAR LST) (CADR LST)) NIL)
          (APPLY '<= (CDR LST)) )
      ((BREAK (LIST '<= (CAR LST) (CADR LST))
           '"Nonnumeric Argument")
          (APPLY '<= (CDR LST)) )
   )
В начало таблицы

    10. Если N1>=N2, N2>=N3,..., Nm-1>=Nm, то функция (>= N1 N2 ... Nm) возвращает Т, иначе - NIL. Например:


   $ (>= 5 9)     $ (>= 3 3.0)
   NIL            T
   $ (>= 4 -7)    $ (>= 3/5 2/3)
   T              NIL

    Данная функция генерирует прерывание по ошибке "Нечисловой аргумент", если какой-либо аргумент не является числом.

В начало таблицы

    11. Функция (MISMATCH LIST1 LIST2 TEST) сравнивает элементы списков LIST1 и LIST2, используя двухэлементный предикат TEST, до тех пор, пока не встретится несоответствие (т.е. пока предикат не вернет NIL) или пока не будет достигнут конец одного или обоих списков. Если TEST есть NIL или не задан, то функция MISMATCH использует EQL-тест.

    Если списки имеют равную длину и несоответствие не найдено, то функция возвращает NIL. Если списки имеют неодинаковую длину, а несоответствие не находится, то функция возвращает длину более короткого списка. В противном случае функция возвращает порядковый номер, начиная с нулевого, первой пары элементов списков, которые не соответствуют друг другу. Например:


   $ (MISMATCH '(A B C D E) '(A B C D E))
   2
   $ (MISMATCH '(5 -4 6 2 ) '(7 -3 9 8) '<)
   NIL
В начало таблицы

    На следующем шаге мы начнем изучать функции, используемые для работы со списками.




Предыдущий шаг Содержание Следующий шаг