Дано :
data Foo =
FooString String
…
class Fooable a where --(is this a good way to name this?)
toFoo :: a -> Foo
Я хочу создать String
пример Fooable
:
instance Fooable String where
toFoo = FooString
Затем GHC жалуется:
Illegal instance declaration for `Fooable String'
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Fooable String'
Если вместо этого я использую [Char]
:
instance Fooable [Char] where
toFoo = FooString
GHC жалуется:
Illegal instance declaration for `Fooable [Char]'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are type *variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Fooable [Char]'
Вопрос :
- Почему я не могу создать String и экземпляр класса типов?
- GHC, похоже, позволит мне уйти от этого, если я добавлю дополнительный флаг. Это хорошая идея?
haskell
ghc
typeclass
type-systems
Джон Ф. Миллер
источник
источник
{-# LANGUAGE FlexibleInstances #-}
(или любую другую директиву) в начало вашего файла .hs.Ответы:
Это потому, что
String
это просто псевдоним типа для[Char]
, который является просто приложением конструктора типа[]
к типуChar
, поэтому он будет иметь форму([] Char)
. который не имеет формы,(T a1 .. an)
потому чтоChar
не является переменной типа.Причина этого ограничения - предотвратить перекрытие экземпляров. Например, допустим, у вас был файл
instance Fooable [Char]
, а потом кто-то пришел и определилinstance Fooable [a]
. Теперь компилятор не сможет определить, какой из них вы хотите использовать, и выдаст вам ошибку.Используя
-XFlexibleInstances
, вы в основном обещаете компилятору, что не будете определять такие экземпляры.В зависимости от того, чего вы пытаетесь достичь, может быть лучше определить оболочку:
newtype Wrapper = Wrapper String instance Fooable Wrapper where ...
источник
instance Fooable [a]
. Есть ли способ заставитьtoFoo
функцию вести себя по-другому, еслиa
это Char?-XOverlappingInstances
которое позволяет это и выбирает наиболее конкретный экземпляр. См. Подробности в руководстве пользователя GHC .Вы сталкиваетесь с двумя ограничениями классических классов типов Haskell98:
Эти обременительные ограничения снимаются двумя языковыми расширениями:
-XTypeSynonymInstances
что позволяет использовать синонимы типов (например,
String
для[Char]
) и:-XFlexibleInstances
которые снимают ограничения на типы экземпляров,
T a b ..
имеющие форму, в которой параметры являются переменными типа.-XFlexibleInstances
Флаг позволяет главе объявления экземпляра упомянуть произвольные вложенные типы.Обратите внимание, что снятие этих ограничений иногда может привести к наложению экземпляров , и в этот момент может потребоваться дополнительное языковое расширение для устранения неоднозначности, что позволит GHC выбрать экземпляр за вас.
Ссылки ::
источник
В большинстве случаев FlexibleInstances - не лучший ответ. Лучшими альтернативами являются упаковка String в новый тип или введение вспомогательного класса следующим образом:
class Element a where listToFoo :: [a] -> Foo instance Element Char where listToFoo = FooString instance Element a => Fooable [a] where toFoo = listToFoo
См. Также: http://www.haskell.org/haskellwiki/List_instance
источник
Добавляя к этим ответам, если вам неудобно снимать ограничения, могут быть случаи, когда имеет смысл обернуть строку в новый тип, который может быть экземпляром класса. Компромисс может заключаться в потенциальном уродстве, когда вам придется оборачивать и развертывать код.
источник