Luke Palmerがexistential type class antipatternと名付けたものにあなたが向いているように聞こえます。まず、あなたはAI-演奏データ型のカップルを持っていると仮定してみましょう:
class AIPlayer a where
name :: a -> String
makeMove :: a -> GameState -> GameState
learn :: a -> GameState -> a
instance AIPlayer AIPlayerGreedy where
name ai = gName ai
makeMove ai gs = makeMoveGreedy (gFactor ai) gs
learn ai _ = ai
instance AIPlayer AIPlayerRandom where
name ai = rName ai
makeMove ai gs = makeMoveRandom (rSeed ai) gs
learn ai gs = ai{rSeed = updateSeed (rSeed ai) gs}
この意志:
data AIPlayerGreedy = AIPlayerGreedy { gName :: String, gFactor :: Double }
data AIPlayerRandom = AIPlayerRandom { rName :: String, rSeed :: Int }
は今、あなたはそれら型クラスの両方のインスタンス作成することにより、これらと連携したいですそのような価値が1つしかないのであれば問題はありませんが、あなたが気付いたように問題に陥る可能性があります。しかし、タイプクラスはあなたに何を買うのですか?あなたの例では、AIPlayer
という異なるインスタンスのコレクションを一様に扱いたいとします。 特定のタイプがコレクションに含まれるかわからないので、gFactor
またはrSeed
のようなものは決して呼び出すことができません。 AIPlayer
によって提供されるメソッドのみを使用することができます。だから、あなたが必要とするすべてはそれらの機能の集合体である、と私たちは、昔ながらのデータ型では最大それらをパッケージ化することができます
data AIPlayer = AIPlayer { name :: String
, makeMove :: GameState -> GameState
, learn :: GameState -> AIPlayer }
greedy :: String -> Double -> AIPlayer
greedy name factor = player
where player = AIPlayer { name = name
, makeMove = makeMoveGreedy factor
, learn = const player }
random :: String -> Int -> AIPlayer
random name seed = player
where player = AIPlayer { name = name
, makeMove = makeMoveRandom seed
, learn = random name . updateSeed seed }
AIPlayer
、その後、ノウハウの集まりです:その名は、どのように新しいAIプレーヤーを学び、生み出す方法について説明します。あなたのデータ型とそのインスタンスは単にAIPlayer
を生成する関数になります。 [greedy "Alice" 0.5, random "Bob" 42]
はよくタイプされているので、すべてをリストに簡単に入れることができます。タイプは[AIPlayer]
です。
あなたはことができ、それは本当、パッケージまで実存タイプを使用して最初のケースです:今
{-# LANGUAGE ExistentialQuantification #-}
data AIWrapper = forall a. AIPlayer a => AIWrapper a
instance AIWrapper a where
makeMove (AIWrapper ai) gs = makeMove ai gs
learn (AIWrapper ai) gs = AIWrapper $ learn ai gs
name (AIWrapper ai) = name ai
、[AIWrapper $ AIPlayerGreedy "Alice" 0.5, AIWrapper $ AIPlayerRandom "Bob" 42]
はよく型付けである:それはタイプ[AIWrapper]
のです。しかし、上記のルーク・パーマーの記事が観察しているように、これは実際にあなたに何も買わず、実際にあなたの人生はより複雑になります。シンプルでノータイプのクラスのケースに相当するので、利点はありません。存在するのは、ラップアップしている構造がもっと複雑な場合にのみ必要です。
おそらくあなたが探しているのは、異種コレクションです。 http://www.haskell.org/haskellwiki/Heterogenous_collectionsの「Showable」の例を参照してください。 – ErikR
については、https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/を参照してください。異機種間のリストの必要性を良い設計に変換する方法。 –