Haskell で Magic The Gathering (MTG) ゲーム エンジンを作成しています。
MTGに馴染みのない方のために説明すると、カードが白(W)、青(U)、黒(B)、赤(R)、緑(G)の5色まで使用できるカードゲームです。
{-# LANGUAGE ViewPatterns #-}
import Data.Set
data Color = W | U | B | R | G
deriving (Show, Eq, Ord)
data Card = Card (Set Color) -- simplified Card type with only its colors
viewColors :: Card -> [Color]
viewColors (Card colors) = toList colors
私がやりたいのは、次のような色のパターンマッチです:
foo :: Card -> String
foo (viewColors -> [W, B]) = "card is white and black"
foo _ = "whatever"
ここまでは順調ですね。しかし、ここで 1 つの問題があります。次のように、ビュー パターンで色の順序を間違って入力できます。
bar :: Card -> String
bar (viewColors -> [B, W]) = "this will never get hit"
bar _ = "whatever"
もちろん、viewColors
この問題を直接解決する方法で書くこともできました。または、ガードを使用することもできますが、使用したくありません。これを行うにはいくつかの方法があります
viewColors :: Card -> (Bool, Bool, Bool, Bool, Bool)
viewColors (Card colors) = let m = (`member` colors)
in (m W, m U, m B, m R, m G)
このソリューションは、型の同形を使用しているBool
が、より短い (および/または意味のある) 識別子を使用している場合でも、パターン マッチング中は非常に冗長です。グリーンカードのマッチングは次のようになります
baz :: Card -> String
baz (viewColors -> (False, False, False, False, True)) = "it's green"
data ColorView = W | WU | WUB | ... all combos here
viewColors :: Card -> ColorView
viewColors (Card colors) = extract correct Colorview from colors
このソリューションには組み合わせ爆発があります。実装するのは非常に悪いようですが、特にcolorViewToList :: ColorView -> [Color]
パターンマッチ後にプログラムによる抽出を許可する場合は、使用すると便利です。
以下が Haskell で近似できるかどうかはわかりませんが、以下が理想的です。
fuz :: Card -> String
fuz (viewColors -> (W :* ())) = "it's white"
fuz (viewColors -> (W :* U :* ())) = "it's white and blue"
fuz (viewColors -> (W :* B :* ())) = "it's white and black"
この種のコードを許可するために、DataKinds、PolyKinds、TypeFamilies、MultiParamTypeClasses、GADT などの高度な言語拡張を喜んで使用します。
このようなことは可能ですか?他に提案されたアプローチはありますか?