В этот разговор вокруг отметки 1:20, Эдвард Кемт упоминает о недостатке "backtracking" типа класса в Haskell. Рассмотрим проблему "установить равенство" (где порядок и кратность не учитываются) реализованы в списках:
equals :: [a] -> [a] -> Bool
По характеру классов типов я не могу обеспечить неэффективное сравнение O (n²), если все, что у нас есть, Eq a
, но эффективно сравнить списки в O (n log n), если мы имеем Ord a
.
Я понял, почему такой объект будет проблематичным. В то же время Эдвард говорит, что есть "трюки, которые вы могли бы сыграть", например, например, типы семейств.
Следовательно, мой вопрос заключается в том, что было бы обходным путем для достижения такого же эффекта:
- предоставляется (неэффективная) реализация по умолчанию
- Если пользователь может предоставить дополнительную информацию о типе, мы "разблокируем" более эффективную реализацию.
Это обходное решение не обязательно должно использовать классы типов.
Изменить. Некоторые люди предложили просто предоставить equals
и efficientEquals
как два разных метода. В общем, я согласен, что это тем более хаскел-идиоматический подход. Однако я не уверен, что это всегда возможно. Например, что, если приведенный выше метод equals является частью класса типа:
class SetLike s where
equals :: Eq a => s a -> s a -> Bool
Предположим, что этот класс был предоставлен кем-то другим, поэтому я не могу просто добавить новую функцию в класс классов. Теперь я хочу определить экземпляр для []
. Я знаю, что []
всегда может обеспечить реализацию equals
независимо от того, какие ограничения существуют в a
, но я не могу сказать, что мой экземпляр использует более эффективную версию, если доступна более подробная информация о a
.
Возможно, я мог бы обернуть список в newtype и пометить его дополнительной информацией о типе?