Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objects of multiple datatypes

I need to implement a chess game for a school assignment, and you have to make an interface that will work for other games on the same board. So, you have to implement chess pieces, but also pieces for other games.

I tried to do this:

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)) }

Then I try to load the begin f the chess game with:

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)

And I get the error "Couldn't match expected type Piece' with actual typeChessPiece' In the first argument of f', namelyRook' In the first argument of Just', namely(f Rook)' In the expression: Just (f Rook)"

So, I've the feeling that the ChessPiece needs to be 'casted' to a (regular) Piece somehow. (I know, I am using terms from imperative programming, but I hope that I make myself clear here, I will be happy to make my question clearer if needed).

Is the construct that I'm trying to make possible? (sort of like a class structure from OO languages, but then applied to datatypes, where one datatype is a sub-datatype from the other, and an object can be two datatypes at the same time. For example a Rook is a ChessPiece and therefore a Piece) What am I doing wrong? Any suggestions on how to implement the structure I need?

like image 429
Ruben Avatar asked Oct 20 '12 16:10

Ruben


People also ask

What are the different data type objects?

The data types can roughly be described as: numbers, booleans, characters, arrays, and structures. Some languages like ActionScript replace characters with "strings". Object oriented languages, such as C++ and Java replace "structures" with "objects".

How do you store elements of different data types?

Yes we can store different/mixed types in a single array by using following two methods: Method 1: using Object array because all types in . net inherit from object type Ex: object[] array=new object[2];array[0]=102;array[1]="csharp";Method 2: Alternatively we can use ArrayList class present in System.

Can lists have multiple object types?

Lists can have multiple object types.

Can objects contain more than one piece of data?

An object can store multiple values, just like an array, but individual values in an object are accessed by a key, not by a numerical index.


1 Answers

What you are after is normally referred to as sub-typing. Most OO languages achieve sub-typing using sub-classes.

Haskell, however, is decidedly not an OO language; in fact, it does not really have any sort of sub-typing at all. Happily, you can usually achieve much the same effect using "parametric polymorphism". Now, "parametric polymorphism" is a scary-sounding term! What does it mean?

In fact, it has a very simple meaning: you can write code that works for all (concrete) types. The Maybe type, which you already know how to use, is a great example here. The type is defined as follows:

data Maybe a = Just a | Nothing

note how it is written as Maybe a rather than just Maybe; the a is a type variable. This means that, when you go to use Maybe, you can use it with any type. You can have a Maybe Int, a Maybe Bool, a Maybe [Int] and even a Maybe (Maybe (Maybe (Maybe Double))).

You can use this approach to define your board. For basic board functions, you do not care about what "piece" is actually on the board--there are some actions that make sense for any piece. On the other hand, if you do care about the type of the piece, you will be caring about what the type is exactly, because the rules for each game are going to be different.

This means that you can define your board with some type variable for pieces. Right now, your board representation looks like this:

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

since you want to generalize the board to any sort of piece, you need to add a type variable instead of specifying ColoredPiece:

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

now you've defined a Board type for any piece type you could possibly imagine!

So, to use this board representation for chess pieces, you need to pass the type of the piece to your new Board type. This will look something like this:

type ChessBoard = Board ColoredPiece

(For reference, type just creates a synonym--now writing ChessBoard is completely equivalent to writing Board ColoredPiece.)

So now, whenever you have a chess board, use your new ChessBoard type.

Additionally, you can write some useful functions that work on any board. For example, let's imagine all you want to do is get a list of the pieces. The type of this function would then be:

listPieces :: Board p -> [p]

You can write a whole bunch of other similar functions that don't care about the actual piece by using type variables like p in your function types. This function will now work for any board you give it, including a Board ColoredPiece, otherwise know as ChessBoard.

In summary: you want to write your Board representation polymorphically. This lets you achieve the same effect as you wanted to try with sub-typing.

like image 128
Tikhon Jelvis Avatar answered Oct 06 '22 22:10

Tikhon Jelvis