1. ホーム
  2. haskell

[解決済み] なぜStringを型クラスのインスタンスにできないのですか?

2023-04-19 08:32:31

質問

与えられた :

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は、もし私が余分なフラグを追加すれば、このことから逃れられるようにすることを望んでいるようです。これは良いアイデアでしょうか?

どのように解決するのですか?

これは String は単なる型のエイリアスで [Char] の型エイリアスで、これは単に型構成子 [] を適用したものです。 Char のような形になるので、これは ([] Char) という形にはなりません。 (T a1 .. an) というのは Char は型変数ではないからです。

この制限の理由は、インスタンスの重複を防ぐためです。例えば、あなたが instance Fooable [Char] を持っていて、後から誰かがやってきて instance Fooable [a] . これでコンパイラはどれを使いたかったのかわからなくなり、エラーになります。

を使うことで -XFlexibleInstances を使うことで、基本的にそのようなインスタンスを定義しないことをコンパイラに約束することになります。

何を達成しようとしているかによりますが、ラッパーを定義する方が良いかもしれません。

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