0

私は型クラスを持っています:

class Wrapper w where
    open :: w -> Map String Int
    close :: Map String Int -> w

あまり役に立たないように見えますが、意味的に異なる種類のsを (type同義語だけでなく) 強く区別するために使用しています。Map String Int

newtype FlapMap = Flap (Map String Int)
newtype SnapMap = Snap (Map String Int)
...

クラスの任意のタイプで動作する関数がまだあります。

  1. この区別を行うためのより良い方法はありますか (おそらくWrapperインスタンスのボイラープレートなしで)?

私はこれをしたい:

instance (Wrapper wrapper) => Show wrapper where
    show w = show $ toList $ open w

多くのボイラープレートShowインスタンスも記述する代わりに。

と を介しFlexibleInstancesUndecidableInstances、GHC は私のインスタンス宣言がすべてに適用されると考える点に私を導きShowますGHC.Show。HaskellWiki と StackOverflow の回答者と HaskellWikiOverlappingInstancesは、完全に安全ではなく、混乱を招く可能性があると確信しています。GHCはそれを示唆していません。

  1. なぜ GHC は最初に fx のどのインスタンスShow Intを選択すればよいかわからないことに文句を言い (それで、なぜコンパイル時に与えた制約を調べないのですか?)、次に、インスタンスがオーバーラップする可能性があると言われ、突然何をすべきかを知ってしまうのでしょうか?

  2. OverlappingInstancesで許可を避けることはできますnewtypeか?

4

1 に答える 1

5

あなたがOverlappingInstances言及したように、これは予測不可能です。とにかく、ここでは役に立たないので、ラッパータイプなしではほとんどこれを行うことはできません.

もちろん、それはかなり満足のいくものではありませんが、なぜそうなるのでしょうか? すでにおわかりのように、GHC はインスタンスを選択するときにインスタンス コンテキストを確認せず、インスタンス ヘッドのみを確​​認します。なんで?さて、次のコードを考えてみましょう:

class Foo a where
  fooToString :: a -> String

class Bar a where
  barToString :: a -> String

data Something = Something

instance Foo Something where
  fooToString _ = "foo something"

instance Bar Something where
  barToString _ = "bar something"

instance Foo a => Show a where
  show = fooToString

instance Bar a => Show a where
  show = barToString

FooまたはBar型クラスを分離して考える場合、上記の定義は理にかなっています。型クラスを実装するものはすべて、 「無料で」インスタンスFooを取得する必要があります。Show残念ながら、同じことがBarインスタンスにも当てはまるため、の有効なインスタンスが2 つshow Somethingあります。

型クラスは常にオープンであるため (実際、Show独自のインスタンスを定義できる場合はオープンにする必要があります)、誰かがやって来て独自の同様のインスタンスを追加し、データ型でインスタンスを作成しないことを知ることは不可能です。あいまいさを作成します。これは事実上、型クラス形式での OO 多重継承による古典的なひし形の問題です。

あなたが得ることができる最善の方法は、関連するインスタンスを提供するラッパータイプを作成することです:

{-# LANGUAGE ExistentialQuantification #-}

data ShowableWrapper = forall w. Wrapper w => ShowableWrapper w

instance Show ShowableWrapper where
  show (ShowableWrapper w) = show . toList $ open w

showWrapper :: Wrapper w => w -> Stringただし、その時点では、独自の関数を作成するよりも多くの利点を得ることはできません。

于 2016-09-06T08:09:21.907 に答える