По сути, проблема в том, что установка типа a
не сообщает компилятору, какой тип b
. Вы можете думать, что, поскольку существует только один экземпляр класса (где a
– это MyString
, а b
– Char
), любой может добавить новые экземпляры в любое время. Таким образом, тот факт, что существует только один экземпляр now, не помогает компилятору решить, какие типы вам нужны.
Решением этого является использование функциональных зависимостей или семейств типов. Последнее является более новым решением и призвано в конечном итоге «заменить» первое, но в настоящее время оба они по-прежнему полностью поддерживаются. Уйдут ли FD когда-нибудь, еще неизвестно. Во всяком случае, с FD:
class Listy a b | a -> b where ...
По сути, это говорит о том, что «для каждого a
может быть только один экземпляр класса». Другими словами, зная a
, вы всегда можете определить b
. (Но не наоборот.) Остальная часть класса выглядит так же, как и раньше.
Альтернативой являются ТФ:
class Listy a where
type Element a :: *
...
instance Listy MyString where
type Element MyString = Char
...
Теперь вместо того, чтобы называть второй тип b
, он называется Element a
. Слово Element
действует как метод класса, который принимает тип списка и возвращает соответствующий тип элемента. Затем вы можете сделать
instance Listy ByteString where
type Element ByteString = Word8
...
instance Listy [x] where
type Element [x] = x
...
instance Ord x => Listy (Set x) where
type Element (Set x) = x
...
и так далее. (Не то чтобы Listy
обязательно имело смысл для всех вышеперечисленных типов; это просто примеры того, как определить класс.)
person
MathematicalOrchid
schedule
17.10.2012