最初に、次のパターンを使用してみてください (MU Terran Terran
その他の自己関係が許可されていると想定しています)。
foo (MU Terran Terran) = ...
foo (MU Terran Zerg) = ...
foo (MU Terran Protoss) = ...
foo (MU Zerg Zerg) = ...
foo (MU Zerg Protoss) = ...
foo (MU Protoss Protoss) = ...
foo (MU x y) = foo (MU y x)
そのように定義された関数には細心の注意を払う必要があります。ケースを網羅的に取得しないと、無限ループになるからです。
2 回目の試行: パターンを一般化する試みが行われましたが、思いついた最良の結果は次のとおりです。
forceSymmetric :: (MU -> Maybe r) -> MU -> r
forceSymmetric f = \p -> case f p of
Nothing -> fromJust (f (swap p))
Just r -> r
foo (MU Terran Terran) = Just ...
foo (MU Terran Zerg) = Just ...
foo (MU Terran Protoss) = Just ...
foo (MU Zerg Zerg) = Just ...
foo (MU Zerg Protoss) = Just ...
foo (MU Protoss Protoss) = Just ...
foo (MU x y) = Nothing
これには、失敗した場合に無限ループではなくエラーが発生するという利点があります。
第三に、より深く試してみてください。問題の核心は、対称性が必要なことです。MU
それがコンストラクタであることを忘れて、単に関数として扱いましょう。この対称法則に従う必要があります。
MU a b == MU b a
==
ここで必ずしも型クラスを意味するわけでEq
はなく、むしろ相互代用性を意味します。ある式を別の式に置き換えても、プログラムの意味に影響を与えるべきではありません。
ええと、代数データ型にはそのプロパティがありません。のような代数データ型コンストラクタのMU
場合、およびのMU a b == MU c d
場合のみ。したがって、関数がとを区別できないようにしたい場合は、型を抽象化して、ユーザーがその内部表現を見ることができないようにする必要があります。a == b
c == d
MU Terran Zerg
MU Zerg Terran
MU
重複を許可して、一度にr個取られるn 個のアイテムの組み合わせの数の式は次のとおりです。と の場合、これは 6 つの組み合わせです。したがって、可能な値が 6 つしかない型、 のような関数、および のような関数を定義する必要があります。これを行う最も簡単な方法は、ソートされたタプルを使用することです。factorial (n + r - 1) / (factorial r * factorial (n - 1))
n = 3
r = 2
MU
toMU :: Race -> Race -> MU
mu a b == mu b a
fromMU :: MU -> (Race, Race)
uncurry toMU . fromMU == id
data Race = Terran | Zerg | Protoss deriving (Eq, Show, Read, Ord);
data SortedPair a = SP a a -- The constructor here needs to be private
makeSortedPair :: Ord a => a -> a -> SortedPair a
makeSortedPair a b | a < b = SP a b
| otherwise = SP b a
breakSortedPair :: SortedPair a a -> (a, a)
breakSortedPair (SP a b) = (a, b)
type MU = SortedPair Race
toMU :: Race -> Race -> MU
toMU = makeSortedPair
fromMU :: MU -> (Race, Race)
fromMU = breakSortedPair
fromMU
これで、が を生成できるが を生成でき(Terran, Zerg)
ないことが保証された(Zerg, Terran)
ので、上記の最初の 2 つの提案から最終的な「包括的な」ケースを除外できます。(ただし、コンパイラはこれについて何も知らないため、網羅的でないパターンについては依然として文句を言います。)