Defining types in Haskell in terms of other types and typeclasses struggling - haskell

Can someone please explain to me how we can define a new type in terms of itself in Haskell. Below is the snippet of code I am struggling to understand. I do not understand how we can define a new type in terms of itself. We are saying Card is a new type with constructors Card Rank Suit. What does this even mean?
Any help would be greatly appreciated.
data Suit = Spades | Hearts | Clubs | Diamonds
deriving (Show, Eq)
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving Show
data Card = Card Rank Suit
deriving Show

We are saying Card is a new type with constructors Card Rank Suit. What does this even mean?
Well, first of all it's wrong. Card is a new type with the single constructor Card; the latter takes two arguments, which are of type Rank and Suit.
The confusing thing here is that you're really dealing with two different things that are both called Card. Let's disambiguate:
data CardT = CardC Rank Suit
deriving Show
That expresses the same definition, but now it's clear that the type and constructor aren't the same thing. CardT lives in the type-level language, CardC lives in the value-level language.
> :t CardC
CardC :: Rank -> Suit -> CardT

Related

How to write the instance for Show of a given datatype shorter?

I´m quite new to Haskell but I wonder how I can write following Code shorter:
data Suite = Club | Heart | Spade | Diamond
data Value = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen |
King | Ace
data Card = Card Suite Value
instance Show Suite where
show Club = "Club"
show Heart = "Heart"
show Spade = "Spade"
show Diamond = "Diamond"
instance Enum Suite where
enumFromTo Club Diamond = [Club, Heart, Spade, Diamond]
enumFromTo Heart Diamond = [Heart, Spade, Diamond]
enumFromTo Club Spade = [Club, Heart, Spade]
instance Show Value where
show Two = "Two"
show Three = "Three"
show Four = "Four"
show Five = "Five"
show Six = "Six"
show Seven = "Seven"
show Eight = "Eight"
show Nine = "Nine"
show Ten = "Ten"
show Jack = "Jack"
show Queen = "Queen"
show King = "King"
show Ace = "Ace"
I want to write the instance for Show Value way shorter. Is there a good way to do this or do I need to write all of it?
I also wonder how i could go from here if I want to define the same instances for Eq Card, Ord Card?
So far
instance Eq Card where
Card _ _ == _ = False
instance Ord Card where
Card Heart Three > Card Heart Two = True
worked, but to write every single possibility would be quite a lot of work.
Thanks for any answers!
Edit: I´m aware of the possiblity to append deriving (Show, etc..) but I don´t want to use it
You've rejected deriving these instances, which is the main way we avoid that much boilerplate. The most obvious remaining elementary way to shorten the Show Value is to use a case expression. This uses an extra line but shortens each case slightly:
instance Show Value where
show x = case x of
Two -> "Two"
Three -> "Three"
-- etc.
Expanding to non-elementary ways, you could
Use generics, either the somewhat more modern version in GHC.Generics or (probably easier in this case) the one in Data.Data. For these, you'll need deriving Generic or deriving Data, respectively, and then you can write (or dig up on Hackage) generic versions of the class methods you need. Neither of these approaches seems very appropriate for a Haskell beginner, but you can work up to them over a number of months.
Use Template Haskell. This is a very advanced language feature, and despite working with Haskell for many years, I have not really begun to grasp how to program with it. Good luck!
If you just want your show method call to print the name of the constructor (as it appears here), there's no need to manually instance them at all. You can automatically derive the Show instance thusly:
data Suit = Club | Heart | Spade | Diamond
deriving Show
data Value = Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen | King | Ace
deriving Show
In some cases, such as Instance Show Value, there is no good way to shorten it without deriving (not counting the ones in dfeuer's answer).
But in others there is! E.g.
for the Enum instances it's enough to define fromEnum and toEnum, all the rest have default definitions. You certainly don't need to list all possibilities in enumFromTo as your example code does.
After you define instance Enum Value, you can write comparison functions by converting to Int and comparing the results:
instance Eq Value where
x == y = fromEnum x == fromEnum y
instance Ord Value where
compare x y = compare (fromEnum x) (fromEnum y)
You can use instances for Value and Suit when writing definitions for Card, e.g.
instance Eq Card where
Card s1 v1 == Card s2 v2 = s1 == s2 && v1 == v2

Cannot parse data constructor in a data/newtype declaration

I have the type Card, consists of suit and rank,
data Suit = A|B deriving (Show, Eq)
data Rank = 1|2 deriving (Show, Eq)
data Card = Card Suit Rank deriving (Show, Eq)
It seems be wrong about the data Rank function, since Int cannot be the type constructor and how to create a right function if my cards are A1|B1|A2|B2
Thank you
It might look as if the statement:
data Suit = A | B
is only defining one thing, the type Suit, as a collection/set of arbitrary objects. Actually, though, it's defining three things: the type Suit and two constructors A and B for creating values of that type.
If the definition:
data Rank = 1 | 2
actually worked, it wouldn't be defining Rank as a collection of the numbers 1 and 2, it would be redefining the numbers 1 and 2 as constructors/values of the new type Rank, and you'd no longer be able to use them as regular numbers. (For example, the expression n + 1 would now be a type error, because (+) expects a number, and 1 would have been redefined as a Rank).
Fortunately or unfortunately, Haskell won't accept numbers as constructor names -- they need to be valid identifiers starting with uppercase letters (or operators that start with a colon).
So, there are two usual approaches to defining a type like Rank that's meant to represent some subset of numbers. The first, as noted in the comments, is to define it much like you already have, but change your numbers into valid identifiers by prefixing with an uppercase letter:
data Rank = R1 | R2
The advantage of this is that it guarantees that only valid ranks can be represented. Here, only ranks 1 and 2 are allowed. If someone tried to write R3 somewhere, it wouldn't work, because that constructor hasn't been defined. The big disadvantage is that this quickly becomes unruly. If these were playing cards, the definition would be:
data Rank = R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 | R9 | R10 | R11 | R12 | R13
and a function to, say, assign point values to cards for rummy would look like:
points :: Rank -> Int
points R1 = 10 -- Ace worth 10
points R2 = 2
points R3 = 3
...
points R9 = 9
points R10 = 10 -- 10 and face cards all worth 10
points R11 = 10
points R12 = 10
points R13 = 10
(In real code, you'd use more advanced Haskell features like a derived Enum instance to deal with this.)
The second approach is to define your rank in terms of an existing numeric type:
data Rank = Rank Int -- actually, `data` would probably be `newtype`
This defines two things, a type named Rank, and a constructor, also named Rank. (This is okay, as types and constructors live in different namespaces.)
In this definition, instead of Rank being defined as a discrete set of values given by explicit constructors with one constructor per value, this definition essential makes the type Rank an Int that's "tagged" with the constructor Rank.
The disadvantage of this approach is that it's now possible to create invalid ranks (since someone can write Rank 14). The advantage is that it's often easier to work with. For example, you can extract the integer from the rank, so points can be defined as:
points :: Rank -> Int
points (Rank 1) = 10 -- Ace is worth 10
points (Rank r) | r >= 10 = 10 -- 10 and face are worth 10
| otherwise = r -- rest are worth their rank
Note that, with this set of definitions:
data Suit = A | B deriving (Show, Eq)
newtype Rank = Rank Int deriving (Show, Eq)
data Card = Card Suit Rank deriving (Show, Eq)
you'd construct Card value using an expression like Card A (Rank 1) for your "A1" card.
There's actually a third approach. Some people might skip defining the Rank type entirely and either write:
data Suit = A | B deriving (Show, Eq)
data Card = Card Suit Int deriving (Show, Eq)
or write the equivalent code using a type alias:
data Suit = A | B deriving (Show, Eq)
type Rank = Int
data Card = Card Suit Rank deriving (Show, Eq)
Note that the type alias here is really just for documentation. Here, Rank and Int are exactly the same type and can be used interchangeably. Using Rank just makes the code easier to understand by making it clear where the programmer intended an Int to stand for a Rank versus an integer used for some other purpose.
The main advantage of this approach is that you can avoid including the word Rank in lots of places (e.g., cards are written Card A 1 instead of Card A (Rank 1), and the definition of points wouldn't need to pattern match the argument on Rank r, etc.) The main disadvantage is that it blurs the distinction between Rank and other integers and makes it easier to make programming errors like using the Rank where you meant to use the points and vice versa.

Haskell interdependent datatype tree aesthetics

I have made an interdependent tree of datatypes as below. PT being the 'root'-datatype. There are functions that should combine the lower datatypes to the root. This way, Giving these functions the type signature (a -> b -> ... -> PT), requires me to include a lot of information to get to lower datatypes (PTCmd CmdSub Hp ...). This descent down the datatype tree is irrelevant and i wouldn't like to include this information in the result.
If I define all the lower datatypes in PT itself, the datatype definition harder to read.
Besides adding worthless information to the result, and a single huge datatype definition, is there another, preferably less of an eyesore, way to have my functions result in the root datatype PT?
data PT = PTCmd Command | PTVal V | PTCon C
deriving (Eq, Show)
data Command = CmdSub Sub | ...
deriving (Eq, Show)
data SubCommand = Hp V C | ...
deriving (Eq, Show)
Perhaps you could define some "smart constructors"; for example:
cmdSub = PTCmd . CmdSub
hp = cmdSub . Hp
If you can afford using GHC 7.8 then you should look at the PatternSynonyms extension, as it addresses your issues quite well.

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?
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.
Tikhon's solution is the way to go. FYI though, note the difference between a type constructor and a data constructor. Right here, for example:
data ChessPiece = King | Queen | Knight | Rook | Bishop | Pawn deriving (Enum, Eq, Show)
data Piece = ChessPiece | OtherGamePiece deriving (Enum, Eq, Show)
This won't work because you're defining a type constructor called ChessPiece in the first line and a data constructor called ChessPiece in the other, and these aren't the same thing. The type constructor says something like: "a ChessPiece type can be a King, or a Queen, or a..." while the data constructor just creates generic data (that also happens to be called ChessPiece).
What you can do is redefine the first data constructor for the Piece type; some generic data called ChessPiece that carries some information about the type ChessPiece under the hood. The following typechecks:
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
and you could alter your functions like so:
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))]
To make the difference between type and data constructors more obvious, here's a limited version that that uses different names for each:
data ChessRoyalty = King | Queen
data Piece = ChessPiece ChessRoyalty | OtherGamePiece
data ColoredPiece = White Piece | Black Piece

Record syntax default value for accessor

As I was writing up an answer just now, I ran across an interesting problem:
data Gender = Male | Female
deriving (Eq, Show)
data Age = Baby | Child | PreTeen | Adult
deriving (Eq, Show, Ord)
data Clothing = Pants Gender Age
| Shirt Gender Age
| Skirt Age -- assumed to be Female
deriving (Show, Eq)
Suppose I wish to write the final data type with record syntax:
data Clothing = Pants {gender :: Gender, age :: Age}
| Shirt {gender :: Gender, age :: Age}
| Skirt {age :: Age}
deriving (Show, Eq)
The problem is, I want gender $ Skirt foo to always evaluate to Female (regardless of foo, which is an Age). I can think of a few ways to accomplish this, but they require that I either
use smart constructors, theoretically allowing Skirt Male foo but not exposing Constructors
define my own gender function
With #1, by not exposing the constructor in the module, I effectively prevent users of the module from taking advantage of record syntax. With #2, I have to forego record syntax entirely, or define an additional function gender', which again defeats record syntax.
Is there a way to both take advantage of record syntax, and also provide a "default", unchangeable value for one of my constructors? I am open to non-record-syntax solutions as well (lenses, perhaps?) as long as they are just as elegant (or moreso).
Is there a way to both take advantage of record syntax, and also provide a "default", unchangeable value for one of my constructors?
In the absence of a convincing counterexample, the answer seems to be "no".
Yes there is a tension between types and data... which by the way shows how thin is the line.
The pratical answer is to use a default instance as indicated in the Haskell Wiki. It does answer your exact question since you must give up direct constructor use.
Thus for your example,
data Age = Baby | Child | PreTeen | Adult | NoAge
data Clothing = Pants {gender :: Gender, age :: Age}
| Shirt {gender :: Gender, age :: Age}
| Skirt {gender :: Gender, age :: Age}
deriving (Show, Eq)
skirt = Skirt { gender=Female, age=NoAge }
then developpers can create new instances with default values, using the copy-and-update facility of the record syntax
newSkirt = skirt { age=Adult }
and gender newSkirt evaluates to Female
I want to stress that this approach leads you to define default values at the type level, which I think is a Good Thing (of course the NoAge constructor is the Nothing of a Maybe Age type).

Resources