Почему существуют отдельные функции / операторы сравнения для строк и чисел?

#generics #polymorphism #scheme #operators #lisp

#дженерики #полиморфизм #схема #операторы #lisp

Вопрос:

Я медленно изучаю Scheme и пересматриваю Haskell, читая онлайн-учебник «Напишите себе схему за 48 часов«. Я только что добрался до этой части, где она знакомит нас с некоторыми операторами сравнения в Scheme.

 ("=", numBoolBinop (==)),
("<", numBoolBinop (<)),
(">", numBoolBinop (>)),
("/=", numBoolBinop (/=)),
(">=", numBoolBinop (>=)),
("<=", numBoolBinop (<=)),
("amp;amp;", boolBoolBinop (amp;amp;)),
("||", boolBoolBinop (||)),
("string=?", strBoolBinop (==)),
("string<?", strBoolBinop (<)),
("string>?", strBoolBinop (>)),
("string<=?", strBoolBinop (<=)),
("string>=?", strBoolBinop (>=)),
 

У меня есть пара вопросов для новичков.
1. Почему существуют отдельные операторы сравнения для разных типов, а не один универсальный оператор или один оператор, который имеет много перегрузок?
2. Возможно ли иметь «общий» оператор равенства, который работает для всех типов, и как он будет реализован? если не для всех типов, то хотя бы для строк и чисел?

Ответ №1:

Чтобы ответить только на второй вопрос: нет, это не так. Для начала существует разница между eq? и любым другим предикатом равенства, и eq? почти неизбежно имеет ненадежное поведение для чисел. Итак, вам нужен как минимум eq? и «семантический» предикат равенства. Но такой предикат семантического равенства не может существовать, потому что язык не может знать, какую семантику вы намереваетесь. Например, что это должно возвращать?

 (let ([c (cons #f #f)])
  (let ([a (cons c c)]
        [b (cons (cons #f #f) (cons #f #f))])
    (general-semantic-equal? a b)))
 

Что ж, должно ли оно возвращать true или false, зависит от того, имеет ли значение в программе, что car и cdr a являются eq? , а те b , которые не являются. И на этот вопрос нельзя ответить, не зная, что делает программа: предикаты равенства зависят от приложения, и лучшее, что может сделать язык, — это предоставить инструментарий, который позволяет его создавать.

Ответ №2:

Схема имеет непересекающиеся типы и решила не проводить общее сравнение. Причиной может быть

  1. В стандартах нет переопределения методов
  2. Исторически сложилось так, что мы используем string-ref или vector-ref подобные материалы вместо одного универсального ref .

Так что вполне естественно, что в нем нет общих процедур сравнения. Единственным исключением являются процедуры сравнения чисел.

Как я упоминал выше, стандарты Scheme не имеют какого-либо механизма переопределения методов, однако невозможно создать общие процедуры. Вам просто нужно создать их поверх других объектно-ориентированных библиотек, таких как Tiny CLOS.

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

 (define (generic= n/s1 n/s2 . rest)
  (cond ((for-all number? (cons* n/s1 n/s2 rest))
         (apply = n/s1 n/s2 rest))
        ((for-all string? (cons* n/s1 n/s2 rest))
         (apply string=? n/s1 n/s2 rest))
        (else (assertion-violation 'generic= "type not supported"))))