2012-09-03 11 views
7

Haskell wih çoklu AI rakiplerine bir kart oyunu simülasyonu yazıyorum. GameParameters -> [AIPlayer] -> GameOutcome gibi bir şeyle ana işlevim olmasını isterim. Ama ana işlevi bir "kütüphane işlevi" olarak düşünmek isterim, böylece yeni bir AIPlayer'ı başka bir şeyi değiştirerek yazabilirim.Haskell'de takılabilir AI

Bir yazım hatası AIPlayer oluşturmayı düşündüğümden, ana işlev AIPlayer a => GameParameters -> [a] -> GameOutcome olur. Ancak bu sadece bir tür AI'nın takılmasına izin verir. Yani bir oyunda birden AIPlayers eklemek için, bir wrappertype

AIWrapper = P1 AIPlayer1 | P2 AIPlayer2 | ... 

instance AIWrapper AIPlayer where 
    gameOperation (P1 x) = gameOperation x 
    gameOperation (P2 x) = gameOperation x 
    ... 

bu sarıcı türü ile mutlu hissetmiyorum tanımlamanız gerekir ve bundan daha iyi bir şey olmalı gibi hissediyorum ya yanlış mıyım?

+1

Belki de aradığınız şey heterojen bir koleksiyon. Http://www.haskell.org/haskellwiki/Heterogenous_collections – ErikR

+2

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. –

cevap

17

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.

+3

+1 Çok güzel bir açıklama! – Landei

+0

teşekkürler, tam olarak aradığım açıklama türü – Ingdas

İlgili konular