5

学校の課題にチェスゲームを実装する必要があります。同じボード上の他のゲームで機能するインターフェイスを作成する必要があります。したがって、チェスの駒だけでなく、他のゲームの駒も実装する必要があります。

私はこれをやろうとしました:

data ChessPiece = King | Queen | Knight | Rook | Bishop | Pawn deriving (Enum, Eq, Show)
data Piece = ChessPiece | OtherGamePiece deriving (Enum, Eq, Show)
data ColoredPiece = White Piece | Black Piece
data Board = Board { boardData :: (Array Pos (Maybe ColoredPiece)) }

次に、チェスゲームの開始を次のようにロードしようとします。

beginBoard = Board (listArray (Pos 0 0, Pos 7 7) (pieces White ++ pawns White ++ space ++ pawns Black ++ pieces Black)) where
    pieces :: (Piece -> ColoredPiece) -> [Maybe ColoredPiece]
    pieces f = [Just (f Rook), Just (f Knight), Just (f Bishop), Just (f Queen), Just (f King), Just (f Bishop), Just (f Knight), Just (f Rook)]
    pawns :: (Piece -> ColoredPiece) -> [Maybe ColoredPiece]
    pawns f = (take 8 (repeat (Just (f Pawn))))
    space = take 32 (repeat Nothing)

Piece' with actual typeそして、「期待されるタイプのChessPieceと一致しませんでした」というエラーが表示されます。「f', namelyRookの最初の引数で」「(fRook)の最初の引数でJust', namely」「式:Just(f Rook)」

ですから、ChessPieceはどういうわけか(通常の)ピースに「キャスト」する必要があると感じています。(私は命令型プログラミングの用語を使用していますが、ここで自分自身を明確にしたいと思います。必要に応じて質問を明確にしたいと思います)。

私が可能にしようとしている構成はありますか?(オブジェクト指向言語のクラス構造のようなものですが、データ型に適用されます。一方のデータ型はもう一方のサブデータ型であり、オブジェクトは同時に2つのデータ型にすることができます。たとえば、RookはChessPieceであるため、ピース)私は何が間違っているのですか?必要な構造を実装する方法について何か提案はありますか?

4

2 に答える 2

10

あなたが求めているものは、通常、サブタイピングと呼ばれます。ほとんどのオブジェクト指向言語は、サブクラスを使用してサブタイピングを実現します。

ただし、Haskellは明らかにオブジェクト指向言語ではありません。実際、サブタイピングはまったくありません。幸いなことに、通常、「パラメトリック多型」を使用してほぼ同じ効果を達成できます。さて、「パラメトリック多型」は恐ろしい言葉です!どういう意味ですか?

実際、これは非常に単純な意味を持っています。すべての(具体的な)タイプで機能するコードを記述できます。Maybeすでに使い方を知っているタイプは、ここでの良い例です。タイプは次のように定義されます。

data Maybe a = Just a | Nothing

Maybe a単なるではなく、どのように書かれているかに注意してくださいMaybe。これaは型変数です。つまり、を使用する場合は、どのタイプでもMaybe使用できます。、、、、およびを使用することもできます。Maybe IntMaybe BoolMaybe [Int]Maybe (Maybe (Maybe (Maybe Double)))

このアプローチを使用して、ボードを定義できます。基本的なボード機能の場合、実際にボード上にある「ピース」を気にする必要はありません。どのピースにも意味のあるアクションがいくつかあります。一方、作品の種類を気にする場合は、ゲームごとにルールが異なるため、正確に種類を気にする必要があります

これは、ピースの型変数を使用してボードを定義できることを意味します。現在、ボードの表現は次のようになっています。

data Board = Board {boardData :: Array Pos (Maybe ColoredPiece)}

ボードをあらゆる種類のピースに一般化したいので、以下を指定する代わりに型変数を追加する必要がありますColoredPiece

data Board p = Board {boardData :: Array Pos p}

Boardこれで、想像できるあらゆるピースタイプのタイプを定義できました。

したがって、このボード表現をチェスの駒に使用するには、駒のタイプを新しいタイプに渡す必要がありますBoard。これは次のようになります。

type ChessBoard = Board ColoredPiece

(参考までtypeに、同義語を作成するだけです。これで、書くことは書くことChessBoardと完全に同等になりますBoard ColoredPiece。)

だから今、あなたがチェス盤を持っているときはいつでも、あなたの新しいChessBoardタイプを使ってください。

さらに、任意のボードで機能するいくつかの便利な関数を作成できます。たとえば、あなたがしたいのはピースのリストを取得することだけだと想像してみましょう。この関数のタイプは次のようになります。

listPieces :: Board p -> [p]

関数型のように型変数を使用することで、実際の部分を気にしない他の同様の関数をたくさん書くことができpます。この関数は、を含むすべてのボードで機能するようになりBoard ColoredPieceましChessBoardた。

Board要約すると、表現を多形的に記述したいとします。これにより、サブタイピングで試したのと同じ効果を得ることができます。

于 2012-10-20T17:02:26.290 に答える
2

Tikhonの解決策は進むべき道です。ただし、参考までに、型コンストラクターとデータコンストラクターの違いに注意してください。ここで、例えば:

data ChessPiece = King | Queen | Knight | Rook | Bishop | Pawn deriving (Enum, Eq, Show)
data Piece = ChessPiece | OtherGamePiece deriving (Enum, Eq, Show)

ChessPiece最初の行で呼び出される型コンストラクターと他の行で呼び出されるデータコンストラクターを定義しているため、これは機能しませんChessPiece。これらは同じものではありません。型コンストラクターは次のように言います:「ChessPiece型は、、、、KingまたはQueen...」のようになりますが、データコンストラクターは汎用データを作成するだけです(これはたまたま呼び出されますChessPiece)。

できることは、Piece型の最初のデータコンストラクターを再定義することです。内部のタイプに関する情報を運ぶ、と呼ばれるいくつかの一般的なデータ。次のタイプチェック:ChessPiece ChessPiece

data ChessPiece   = King | Queen | Knight | Rook | Bishop | Pawn deriving (Enum, Eq, Show)
data Piece        = ChessPiece ChessPiece | OtherGamePiece  -- note the change 
data ColoredPiece = White Piece | Black Piece

そして、あなたはそのようにあなたの機能を変えることができます:

pieces :: (Piece -> ColoredPiece) -> [Maybe ColoredPiece]
pieces f = [Just (f (ChessPiece Rook)), Just (f (ChessPiece Knight)), Just (f (ChessPiece Bishop)), Just (f (ChessPiece Queen)), Just (f (ChessPiece King)), Just (f (ChessPiece Bishop)), Just (f (ChessPiece Knight)), Just (f (ChessPiece Rook))]

タイプコンストラクタとデータコンストラクタの違いをより明確にするために、それぞれに異なる名前を使用する限定バージョンを次に示します。

data ChessRoyalty = King | Queen
data Piece        = ChessPiece ChessRoyalty | OtherGamePiece
data ColoredPiece = White Piece | Black Piece
于 2012-10-20T17:13:29.437 に答える