Luke Palmer'ın existential type class antipattern adını verdiği yönteme giden yoldaki gibi olabilirsiniz.
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}
Bu irade:
data AIPlayerGreedy = AIPlayerGreedy { gName :: String, gFactor :: Double }
data AIPlayerRandom = AIPlayerRandom { rName :: String, rSeed :: Int }
Şimdi, onlara bir tür sınıfın iki örneği yaparak bu birlikte çalışmak istiyoruz: İlk olarak, AI yapma veri türlerinin bir çift var olduğunu varsayalım Eğer sadece böyle bir değeriniz varsa, ancak fark ettiğiniz gibi, problemlerle karşılaşmanıza neden olabilirsiniz. Tip sınıfı size ne alıyor? Örneğinizde, AIPlayer
'un farklı örneklerinin bir koleksiyonunu tek tip bir şekilde ele almak istiyorsunuz. Koleksiyonda hangi spesifik türünün bulunacağını bilmediğinizden, gFactor
veya rSeed
gibi hiçbir şeyi arayamayacaksınız; Sadece AIPlayer
tarafından sağlanan yöntemleri kullanabileceksiniz. Yani tek ihtiyacınız olan fonksiyonları bir koleksiyon ve biz bir düz eski veri türü kadar olanlar paketleyebilirsiniz:
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 }
bir AIPlayer
, o zaman, know-how topluluğudur: Adından nasıl harekete geçmek ve yeni bir AI oyuncuyu öğrenmek ve üretmek. Veri tipleriniz ve örnekleri sadece AIPlayer
s üreten işlevler haline gelir; [greedy "Alice" 0.5, random "Bob" 42]
iyi yazılmıştır: [AIPlayer]
türünde olduğu gibi her şeyi bir listeye kolayca koyabilirsiniz.
{-# 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
Şimdi [AIWrapper $ AIPlayerGreedy "Alice" 0.5, AIWrapper $ AIPlayerRandom "Bob" 42]
iyi yazmış olduğu: Sen can
, bir varoluşsal türüyle paket yukarı ilk vaka, doğrudur o tip [AIWrapper]
yüzünden. Ancak Luke Palmer'ın yukarıda yazdığı gibi gözlemlediği gibi, bu aslında hiçbir şey satın almıyor ve aslında hayatınızı daha da karmaşıklaştırıyor. Daha basit, no-tip-sınıf davayla eşdeğer olduğu için, avantajı yoktur; varoluşçular sadece, sarım yaptığınız yapı daha karmaşıksa gereklidir.
Belki de aradığınız şey heterojen bir koleksiyon. Http://www.haskell.org/haskellwiki/Heterogenous_collections – ErikR
adresindeki 'Gösterilebilir' örneğine bakın. Https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/ adresine bakınız. heterojen listeler için ihtiyaç iyi bir tasarıma nasıl dönüştürülür. –