Stringを型クラスのインスタンスにできないのはなぜですか?


85

与えられた

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]'

質問

  • 文字列と型クラスのインスタンスを作成できないのはなぜですか?
  • フラグを追加すれば、GHCはこれを回避させてくれるようです。これは良い考えですか?

6
これは私が賛成してお気に入りとしてマークする種類の質問です。そうしないと、近い将来に質問することがわかっているからです;)
Oscar Mederos

3
追加のフラグについて:GHCを信頼し、フラグの機能を理解している限り、おそらくそれは良い考えです。Yesodが思い浮かびます。Yesodアプリを作成するときは常にOverloadedStringsプラグマを使用することをお勧めします。また、QuasiQuotesはYesodルーティングルールに必要です。コンパイル時のフラグの代わりに、{-# LANGUAGE FlexibleInstances #-}.hsファイルの先頭に(または他のプラグマを)置くこともできることに注意してください。
ダンバートン

回答:


65

これは、あるStringのためだけのタイプの別名である[Char]型コンストラクタのアプリケーションだけである、[]タイプのCharため、これは形式になり([] Char)。は型変数ではない(T a1 .. an)ため、これは形式でCharはありません。

この制限の理由は、インスタンスの重複を防ぐためです。たとえば、あなたが。を持っていてinstance Fooable [Char]、後で誰かがやって来て、を定義したとしましょうinstance Fooable [a]。これで、コンパイラーは使用したいものを判別できなくなり、エラーが発生します。

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

達成しようとしていることによっては、ラッパーを定義する方がよい場合があります。

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

4
議論のために、私も本当に欲しかったとしましょうinstance Fooable [a]。がCharのtoFoo場合、関数の動作を変える方法はありaますか?
ジョンF.ミラー

7
@John:-XOverlappingInstancesこれを可能にし、最も具体的なインスタンスを選択する拡張機能があります。詳細については、GHCユーザーガイドを参照してください
hammar

18

従来のHaskell98型クラスには2つの制限があります。

  • インスタンスで型の同義語を許可しません
  • それらは、型変数を順番に含まないネストされた型を許可しません。

これらの厄介な制限は、2つの言語拡張によって解除されます。

  • -XTypeSynonymInstances

これにより、型シノイム(のようString[Char])を使用できます。

  • -XFlexibleInstances

これによりT a b ..、パラメーターが型変数である形式のインスタンス型に対する制限が解除されます。この-XFlexibleInstancesフラグにより​​、インスタンス宣言の先頭で任意のネストされた型に言及できます。

これらの制限を解除すると、インスタンス重複する場合があることに注意してください。その時点で、あいまいさを解決するために追加の言語拡張が必要になり、GHCがインスタンスを選択できるようになります。


参照::


4

ほとんどの場合、FlexibleInstancesは適切な答えではありません。より良い代替策は、Stringをnewtypeでラップするか、次のようなヘルパークラスを導入することです。

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


2

これらの回答に加えて、制限を解除することに抵抗がある場合は、文字列をクラスのインスタンスである可能性のあるニュータイプでラップすることが理にかなっている場合があります。トレードオフは潜在的な醜さであり、コードをラップおよびアンラップする必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.