#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:
Схема имеет непересекающиеся типы и решила не проводить общее сравнение. Причиной может быть
- В стандартах нет переопределения методов
- Исторически сложилось так, что мы используем
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"))))