2

関数の多態性パラメーターのタイプに応じて、異なる出力が必要だとしましょう。私の最初の試みは、いくつかの不可解なエラーメッセージで失敗します:

choice :: a -> Int
choice (_ :: Int) = 0
choice (_ :: String) = 1
choice _ = 2

ただし、目的の型をさまざまなデータ コンストラクターでラップし、それらをパターン マッチングで使用することで、簡単に修正できます。

data Choice a = IntChoice Int | StringChoice String | OtherChoice a

choice :: Choice a -> Int
choice (IntChoice _) = 0
choice (StringChoice _) = 1
choice (OtherChoice _) = 2

質問:これを回避する方法を知っていますか? Haskell2010、GHC、または最初のバリアント (または同様のもの) を使用できるようにする拡張機能はありますか?

4

2 に答える 2

5

これは、2 つの異なる種類のポリモーフィズムを混同しています。必要なのは、型クラスを介して行われるアドホック ポリモーフィズムです。型の関数のポリモーフィズムの種類a -> Intは、パラメトリック ポリモーフィズムです。パラメトリック ポリモーフィズムでは、 の 1 つの関数定義が可能なすべてのtypeに対して機能するchoice必要があります。この場合、これは type の値について何も知らないため、実際には type の値を使用できないことを意味するため、 のような定数関数でなければなりません。これにより、関数の型を調べるだけで、実際に関数ができることについて非常に強力な保証が得られます (このプロパティはparametricityと呼ばれます)。aachoicechoice _ = 3

型クラスを使用すると、例を次のように実装できます。

class ChoiceClass a where
  choice :: a -> Int

instance ChoiceClass Int where
  choice _ = 0

instance ChoiceClass String where
  choice _ = 1

instance ChoiceClass a where
  choice _ = 2

ここで、この型クラスのアプローチは、特に使い始めたばかりの人が使用したい場合は特に、間違っていることが多いことを指摘しておく必要があります。質問のタイプのような単純なタイプを避けるために、絶対にやりたくありませんChoice。多くの複雑さが追加される可能性があり、最初はインスタンスの解決が混乱する可能性があります。型クラス ソリューションを機能させるには、2 つの拡張機能をオンにする必要があることに注意しFlexibleInstancesてください。型クラスは「オープンワールド」の前提で機能するため、これも必要です (つまり、後で誰でも新しい型のインスタンスを追加することができ、これを考慮する必要があります)。これは必ずしもそうではありませんTypeSynonymInstancesString[Char]OverlappingInstances悪いことですが、ここでは、はるかに単純なデータ型ソリューションよりも型クラス ソリューションを使用することによって引き起こされる複雑さが忍び寄る兆候です。OverlappingInstances特に、物事を考えたり操作したりするのが難しくなる可能性があります。

于 2015-05-19T18:23:28.613 に答える
4

質問: これを回避する方法を知っていますか? Haskell2010、GHC、または最初のバリアント (または同様のもの) を使用できるようにする拡張機能はありますか?

いいえ、Haskell 2010 にも、型の関数を記述できる GHC 拡張機能によって提供される機能もありません。

choice :: a -> Int

その戻り値は、その引数の型によって異なります。このような機能が将来存在しないことも期待できます。

Int実行時に GHC の内部データ表現を検査するハックがあっても、 typeの値と、型が の newtype である値を区別することは不可能ですInt。これらの型は同一の実行時表現を持ちます。

関数によって返されるInt値は実行時に存在する値であるため、実行時に存在する別の値によって決定する必要があります。それはどちらかである可能性があります

  1. あなたの例のような通常の値、data Choice a = IntChoice Int | StringChoice String | OtherChoice a; choice :: Choice a -> Intまたは

  2. David Youngの回答のようなカスタムクラス、または組み込みクラスのいずれかを使用した型クラス辞書Typeable

    choice :: Typeable a => a -> Int
    choice a
      | typeOf a == typeOf (undefined :: Int)    = 0
      | typeOf a == typeOf (undefined :: String) = 1
      | otherwise                                = 2
    
于 2015-05-19T18:49:12.103 に答える