development

String을 타입 클래스의 인스턴스로 만들 수없는 이유는 무엇입니까?

big-blog 2020. 9. 19. 11:49
반응형

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 및 typeclass의 인스턴스를 만들 수없는 이유는 무엇입니까?
  • 추가 플래그를 추가하면 GHC가 기꺼이이 문제를 해결해 줄 것 같습니다. 이것이 좋은 생각입니까?

이것은 String형식 [Char]에 대한 형식 생성자의 응용 프로그램 인에 대한 형식 별칭 일 뿐이 므로 []형식 Char이 될 수 있기 때문입니다 ([] Char). 형식 변수가 아니기 (T a1 .. an)때문에 형식 Char이 아닙니다.

이 제한의 이유는 중복 인스턴스를 방지하기위한 것입니다. 예를 들어,을 가지고 있는데 instance Fooable [Char]나중에 누군가가 와서 instance Fooable [a]. 이제 컴파일러는 사용하려는 것을 파악할 수 없으며 오류가 발생합니다.

를 사용 -XFlexibleInstances하면 기본적으로 그러한 인스턴스를 정의하지 않겠다고 컴파일러에 약속하게됩니다.

수행하려는 작업에 따라 래퍼를 정의하는 것이 더 나을 수 있습니다.

newtype Wrapper = Wrapper String
instance Fooable Wrapper where
    ...

고전적인 Haskell98 유형 클래스의 두 가지 제한 사항에 직면 해 있습니다.

  • 인스턴스에서 유형 동의어를 허용하지 않습니다.
  • 차례로 유형 변수를 포함하지 않는 중첩 유형을 허용하지 않습니다.

이러한 번거로운 제한은 두 가지 언어 확장으로 해제됩니다.

  • -XTypeSynonymInstances

형식 동의어 (예 : Stringfor [Char]) 를 사용할 수 있습니다 .

  • -XFlexibleInstances

which lift the restrictions on instance types being of the form T a b .. where the parameters are type variables. The -XFlexibleInstances flag allows the head of the instance declaration to mention arbitrary nested types.

Note that lifting these restrictions can sometimes lead to overlapping instances, at which point, an additional language extension might be needed to resolve the ambiguity, allowing GHC to pick an instance for you.


References::


FlexibleInstances are not a good answer in most cases. Better alternatives are wrapping the String in a newtype or introduce a helper class like so:

class Element a where
   listToFoo :: [a] -> Foo

instance Element Char where
   listToFoo = FooString

instance Element a => Fooable [a] where
   toFoo = listToFoo

See also: http://www.haskell.org/haskellwiki/List_instance


Adding to these answers, if you are not comfortable with lifting the restrictions, there may be cases where it could make sense to wrap your String in a newtype, which can be an instance of a class. The tradeoff would be potential ugliness, having to wrap and unwrap in your code.

참고URL : https://stackoverflow.com/questions/5941701/why-can-i-not-make-string-an-instance-of-a-typeclass

반응형