Почему я не могу сделать String экземпляром класса типов?

Учитывая

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, кажется, готов позволить мне сойти с рук, если я добавлю дополнительный флаг. Это хорошая идея?
82 голоса | спросил John F. Miller 9 Maypm11 2011, 23:45:50

4 ответа


0

Это потому, что String это просто псевдоним типа для [Char], который является просто применением конструктора типа [] для типа Char, поэтому это будет иметь вид ([] Char). который не имеет форму (T a1 .. an), потому что Char не является переменной типа.

Причиной такого ограничения является предотвращение перекрытия экземпляров. Например, допустим, у вас есть instance Fooable [Char], а затем кто-то позже пришел и определил instance Fooable [a]. Теперь компилятор не сможет определить, какой из них вы хотите использовать, и выдаст ошибку.

Используя -XFlexibleInstances, вы в основном обещаете компилятору, что не будете определять такие экземпляры.

В зависимости от того, что вы пытаетесь выполнить, может быть лучше определить оболочку:

newtype Wrapper = Wrapper String
instance Fooable Wrapper where
    ...
ответил hammar 9 Maypm11 2011, 23:52:41
0

Вы сталкиваетесь с двумя ограничениями классических классов типов Haskell98:

  • они запрещают синонимы типов в случаях
  • они запрещают вложенные типы, которые в свою очередь не содержат переменных типа.

Эти обременительные ограничения снимаются двумя языковыми расширениями:

    -XTypeSynonymInstances литий>

, который позволяет использовать синонимы типа (например, String для [Char]) и:

    -XFlexibleInstances литий>

которые снимают ограничения на типы экземпляров в форме T a b .., где параметры являются переменными типа. Флаг -XFlexibleInstances позволяет заголовку объявления экземпляра упоминать произвольные вложенные типы.

Обратите внимание, что снятие этих ограничений иногда может привести к перекрывающиеся экземпляры , после чего может потребоваться дополнительное расширение языка для устранения неоднозначности, позволяющее GHC выбрать экземпляр для вас.


Литература:

ответил Don Stewart 9 Maypm11 2011, 23:52:15
0

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 р>

ответил Lemming 3 MarpmSun, 03 Mar 2013 23:55:42 +04002013-03-03T23:55:42+04:0011 2013, 23:55:42
0

В дополнение к этим ответам, если вам неудобно снимать ограничения, могут быть случаи, когда имеет смысл обернуть вашу строку в новый тип, который может быть экземпляром класса. Компромисс был бы потенциальным уродством, вынужденным переносить и разворачивать ваш код.

ответил kowey 10 Maypm11 2011, 12:32:14

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132