Haskell 101 | What do the Deriving Keywords mean? - haskell

Essentially practically I'm trying to implement a custom data type that is a subset of the string class (e.g. so I can do some type checking for error input). But I cannot for the life of me find anywhere that just explains what each type keyword means. According to here: Haskell Docs these are the 7 basic ones: Eq, Ord, Enum, Ix, Bounded, Read, and Show. And aside from Show which is needed for print statements and Eq which needed for boolean style comparison checks, I'm not completely certain on the other 5, and google has not been very much help. So I'm hoping y'all can shed some light and maybe point me in the correct direction.
So questions:
What are these 7 basic derives / what does adding them do?
Is there a way within ghci I can run something like derives String or derives "abc"?
Here's the code I'm working on. Essentially I've just created this Card data type which as you can see is just a string that does some more strict parameter checks. And what I'm trying to do is pass it to match which previously accepted 3 strings as an argument (now 3 Cards). But in order to use the string manipulation syntax like breaking it down into a list of characters, I believe I need to identify the appropriate derive keyword so that it behaves in this manner.
match :: Card -> Card -> Card -> Bool
match [] [] [] = True
match [a] [b] [c] = (a == b && b == c)
|| (a /= b && b /= c && a /= c)
match (a:as) (b:bs) (c:cs) = match [a] [b] [c]
&& match as bs cs
data Card = Card String
deriving (Show,Eq)
card :: String -> Card
card x | length x /= 4 = error "Card input must be 4 characters."
| (x!!0 /= 'o') && (x!!0 /= 's') && (x!!0 /= 'd') = error "char 0 (shape) must be o s or d."
| (x!!1 /= '1') && (x!!1 /= '2') && (x!!1 /= '3') = error "char 1 (number) must be 1 2 or 3."
| (x!!2 /= 'r') && (x!!2 /= 'p') && (x!!2 /= 'g') = error "char 2 (color) must be r p or g."
| (x!!3 /= 'f') && (x!!3 /= 's') && (x!!3 /= 'o') = error "char 3 (shade) must be f s or o."
| otherwise = Card x
(Updated Example #1)
data Card = Card Shape Number Color Shade deriving (Show, Eq)
data Shape = Oval | Squiggle | Diamond deriving Eq
instance Show Shape where
show Oval = "Oval"
show Squiggle = "Squiggle"
show Diamond = "Diamond"
data Number = One | Two | Three deriving Eq
instance Show Number where
show One = "One"
show Two = "Two"
show Three = "Three"
data Color = Red | Pink | Green deriving Eq
instance Show Color where
show Red = "Red"
show Pink = "Pink"
show Green = "Green"
data Shade = Full | Half | Empty deriving Eq
instance Show Shade where
show Full = "Full"
show Half = "Half"
show Empty = "Empty"
shape :: Char -> Either ShapeError Shape
shape 'o' = Right Oval
shape 's' = Right Squiggle
shape 'd' = Right Diamond
shape x = Left (NotOSD x)
number :: Char -> Either NumberError Number
number '1' = Right One
number '2' = Right Two
number '3' = Right Three
number x = Left (Not123 x)
color :: Char -> Either ColorError Color
color 'r' = Right Red
color 'p' = Right Pink
color 'g' = Right Green
color x = Left (NotRPG x)
shade :: Char -> Either ShadeError Shade
shade 'f' = Right Full
shade 's' = Right Half
shade 'o' = Right Empty
shade x = Left (NotFSO x)
card :: String -> Either SetError Card
card [shp, n, c, shd] = Card <$> shape shp <*> number n <*> color c <*> shade shd
card x = Left (NotCard x)
data CardError = NotCard String
instance Show CardError where
show (NotCard x) = "Card must be 4 characters long, not " ++ show x
data SetError = CardError | ShapeError | NumberError | ColorError | ShadeError deriving Eq
data ShapeError = NotOSD Char
instance Show ShapeError where
show (NotOSD x) = "Shape must be o, s, or d, not " ++ show x
data NumberError = Not123 Char
instance Show NumberError where
show (Not123 x) = "Number must be 1, 2, or 3, not " ++ show x
data ColorError = NotRPG Char
instance Show ColorError where
show (NotRPG x) = "Color must be r, p, or g, not " ++ show x
data ShadeError = NotFSO Char
instance Show ShadeError where
show (NotFSO x) = "Shade must be f, s, or o, not " ++ show x
Current Error
match.hs:84:34:
Couldn't match type ‘ShapeError’ with ‘SetError’
Expected type: Either SetError Shape
Actual type: Either ShapeError Shape
In the second argument of ‘(<$>)’, namely ‘shape shp’
In the first argument of ‘(<*>)’, namely ‘Card <$> shape shp’
match.hs:84:48:
Couldn't match type ‘NumberError’ with ‘SetError’
Expected type: Either SetError Number
Actual type: Either NumberError Number
In the second argument of ‘(<*>)’, namely ‘number n’
In the first argument of ‘(<*>)’, namely
‘Card <$> shape shp <*> number n’
match.hs:84:61:
Couldn't match type ‘ColorError’ with ‘SetError’
Expected type: Either SetError Color
Actual type: Either ColorError Color
In the second argument of ‘(<*>)’, namely ‘color c’
In the first argument of ‘(<*>)’, namely
‘Card <$> shape shp <*> number n <*> color c’
match.hs:84:73:
Couldn't match type ‘ShadeError’ with ‘SetError’
Expected type: Either SetError Shade
Actual type: Either ShadeError Shade
In the second argument of ‘(<*>)’, namely ‘shade shd’
In the expression:
Card <$> shape shp <*> number n <*> color c <*> shade shd
match.hs:85:16:
Couldn't match expected type ‘SetError’
with actual type ‘CardError’
In the first argument of ‘Left’, namely ‘(NotCard x)’
In the expression: Left (NotCard x)
Failed, modules loaded: none.

When writing Haskell, don't be afraid of defining lots of types and lots of small functions. Small functions are easier to understand, and can be combined in various ways to define larger functions.
Do you care about the typeclasses...
To get your immediately question out of the way, the Show instance is only used for producing a String from some value. Eq is used to allow comparing two values of the same type with ==. The other classes you can derive instances for (without GHC-specific extensions) are
Read
Ord
Enum
Bounded
Read is like the inverse of Show, but is generally not used. (The parsers I show below are easier to write than Read instances, and you won't be able to make use of derived Read instances for most of the types you'll define.) The other three may be relevant to other parts of your program, but not to any of the code in your question.
Derived Show instances basically just convert the data constructor name to a string, but as a point of good style, that string should be valid Haskell code. Derived Eq instances just check if the two data constructors are the same or not. Definitions for data constructors that take arguments are derived recursively: show (Card x) would be defined using "Card" and show x, while Card c1 == Card c2 would be define as c1 == c2.
Most of your question, though, is about pattern matching (as mentioned in the comments), which has nothing to do with type classes.
...or the types?
Let's start with your four basic concepts: shape, number, color, and shade. Define a separate type for each of them. Here's the type for Shape as an example:
data Shape = ShapeO | ShapeS | ShapeD deriving (Show, Eq)
Use descriptive names for data constructors where possible (is O really short for Oval? If so, use Oval), and keep in mind that the names must be globally unique (within a module, anyway), so you can't us O for both Shape and Shade. Sometimes the strings derived from the constructor names will be sufficient for your Show instance sometimes not. If not, rather than defining a Show instance, write your own Thing -> String function instead.
Whether you deriving the Show instance or write it manually probably depends on the data constructor names you choose and what strings you want from the values. The derived Eq instances will almost certainly be sufficient, as they do not depend on the names you use for constructor.
(As an aside, Number is tricky because you can't use 1, 2, or 3 as data constructor names. Unless you need to do math with the numbers, you might consider something like data Number = One | Two | Three instead of the overly broad data Number = Number Int.)
Now your Card type can a simple composition of your four attribute types, not just a wrapper around the raw string.
data Card = Card Shape Number Color Shade deriving (Show, Eq)
(But regarding Show, any of the attribute that have their own string-conversion function might compel you to write a Card -> String function of your own instead of relying on the Show instance.)
Parsing: strings to values
You'll want functions that parse a character into an appropriate value, not just check if it could represent an appropriate value. Sometimes this is possible ('o' for ShapeO), sometimes it is not ('x' does not represent a Shape. So your parser should account for this, but not by simply raising an exception with error. Instead, let the return type tell the caller what happened, and let them decide whether the program needs to be terminated. For example,
shape :: Char -> Either String Shape
shape 'o' = Right ShapeO
shape 's' = Right ShapeS
shape 'd' = Right ShapeD
shape x = Left $ "Shape must be o, s, or d, got ++ show x
The fact that shape returns a Right or Left value is often enough information for the caller to decide what to do next; the error message wrapped by Left is more for reporting errors to the user.
Once you have all the parsers for the individual attributes, the parser for a Card becomes almost trivial, thanks to the Applicative instance for Either String types.
card :: String -> Either String Card
card [shp, n, c, shd] = Card <$> shape shp <*> number n <*> color c <*> shade shd
card x = Left $ "Card must e 4 characters long, got " ++ show x
If any of the attributes produce a Left value, card will return the Left value of the first attribute that fails to parse. Only when the input string has exactly 4 of the correct characters will char produce a Card value wrapped with Right.
You might decide to define dedicated error types as well, rather than using arbitrary strings. For example,
data ShapeError = NotOSD Char
errorMessage :: ShapeError -> String
errorMessage (NotOSD x) = "Shape must be o, s, or d, not " ++ show x
then
shape :: String -> Either ShapeError Shape
shape 'o' = Right ShapeO
shape 's' = Right ShapeS
shape 'd' = Right ShapeD
shape x = Left (NotOSD x)
Basically, capture the information about the error in the error type, and let its Show instance produce a human-readable string with that information if needed.
Things are equal if their parts are equal
match is similarly trivial, making use of the Eq instance derived for Card, which is derived from the Eq instances for all the attribute types.
match :: Card -> Card -> Card -> Bool
match c1 c2 c3 = c1 == c2 && c2 == c3 || (c1 /= c2 && c2 /= c3 && c3 /= c1)

Related

Trying to search for an element in a listed tuple that has a new datatype

I've created a new datatype Board:
data Board a = Grid [(Position, Maybe a)]
deriving (Eq, Show)
where Position is its own datatype:
data Position = NW | N | NE | W | M | E | SW | S | SE
deriving (Eq, Ord, Show)
Now I'm trying to create a function label, that takes a Position and Board and returns the label at the given position (wrapped using Just) or Nothing if the given position is empty.
I was thinking of implementing a new function Search to do this.
search :: (Eq a) => a -> [(a,b)] -> Maybe b
search _ [] = Nothing
search x ((a,b):xs) = if x == a then Just b else search x xs
But I don't know how to pass in the List [(a,b)] from my Board input. I tried:
label :: Position -> Board a -> Maybe a
label p b = Search p b
and got the error:
* Couldn't match expected type: [(Position, a)]
with actual type: Board a
* In the second argument of `lookup', namely `b'
In the expression: lookup p b
In an equation for `label': label p b = lookup p b
* Relevant bindings include
b :: Board a (bound at A6.hs:21:9)
label :: Position -> Board a -> Maybe a (bound at A6.hs:21:1)
Perhaps there's an easier way to go about this, but this is the only way I could think of.
(Aplet123 pointed out a mistake, since updated and updated the error produced)
You need to look into your data type under the wraps to find the actual datum there,
label :: Position -> Board a -> Maybe a
label p (Grid b) = search p b
-- ^^^^
Function names in Haskell must not be capitalized. That is reserved for types and data constructors.
The above will give you another type error but you'll be able to tweak it, I believe, to get it fixed. For starters, enter the definition without the type signature, to see what type is inferred for it.

instance declaration and convert string to Maybe type

An guessing and answering game.
Each Card comprises a Suit, one of A,B,C,D,E,F,G, and a Rank, one of 1|2|3.
I need to have a function to guarantee input(String) whether is valid type. And also write an instance declaration so that the type is in the Show class.
I am not sure about the function toCard, how to express "String" in the function and meet it with the condition.
data Suit = A|B|C|D|E|F|G
deriving (Show , Eq)
data Rank = R1|R2|R3
deriving (Show, Eq)
data Card = Card Suit Rank
deriving (Show, Eq)
instance Show Card where show (Card a b)
= show a ++ show (tail show b)
toCard :: String -> Maybe Card
toCard all#(x:xs)
| (x=A|B|C|D|E|F)&&(xs==1|2|3) = Just Card
| otherwise = Nothing
edit toCard function, input should be any String, so i use a list expression, but it seems to be not correct, cause i try it in ghci, (x=A|B|C|D|E|F)&&(y==1|2|3) is not valid
1) Firstly,
instance Show Card where show (Card a b)
= show a ++ show (tail show b)
You have automatically derived a Show instance for Card, so this will conflict (you can only have 1 instance), and further it won't compile. The show should go on a new line, and tail should be applied to the result of show b.
instance Show Card where
show (Card a b) = show a ++ " " + tail (show b)
2) Secondly,
toCard :: String -> Maybe Card
toCard all#(x:xs)
| (x=A|B|C|D|E|F)&&(xs==1|2|3) = Just Card
| otherwise = Nothing
The syntax (x=A|B|C|D|E|F)&&(xs==1|2|3) is pretty wild, and certainly not valid Haskell. The closest approximation would be something like, x `elem` ['A','B','C','D','E','F'] && xs `elem` ["1","2","3"], but as you can see this rapidly becomes boilerplate-y. Also, Just Card makes no sense - you still need to use the x and xs to say what the card actually is! eg. Just $ Card x xs (though that still won't work because they're still character/string not Suit/Rank).
One solution would be to automatically derive a Read instance on Rank, Suit, and Card. However, the automatic derivation for read on Card would require you to input eg. "Card A R1", so let's try using the instance on Rank and Suit to let us write a parser for Cards that doesn't require prefixed "Card".
First attempt:
toCard :: String -> Maybe Card
toCard (x:xs) = Just $ Card (read [x] :: Suit) (read xs :: Rank)
Hmm, this doesn't really allow us to deal with bad inputs - problem being that read just throws errors instead of giving us a Maybe. Notice however that we use [x] rather than x because read applies to [Char] and x :: Char. Next attempt:
import Text.Read (readMaybe)
toCard :: String -> Maybe Card
toCard [] = Nothing
toCard (x:xs) = let mSuit = readMaybe [x] :: Suit
mRank = readMaybe xs :: Rank
in case (mSuit, mRank) of
(Just s, Just r) -> Just $ Card s r
_ -> Nothing
This copes better with bad inputs, but has started to get quite long. Here's two possible ways to shorten it again:
-- using the Maybe monad
toCard (x:xs) = do mSuit <- readMaybe [x]
mRank <- readMaybe xs
return $ Card mSuit mRank
-- using Applicative
toCard (x:xs) = Card <$> readMaybe [x] <*> readMaybe xs
A parser library, though it comes with a steeper learning curve, makes this simpler. For this example, we'll use Text.Parsec, from the parsec library. Import it, and define a type alias for using in defining your parsers.
import Text.Parsec
type Parser = Parsec String () -- boilerplate
Parsec String () indicates a type of parser that consumes a stream of characters, and can produce a value of type () after parsing is complete. (In this case, we only care about the parsing, not any computation done along side the parsing.)
For your core types, we'll define a Show instant by hand for Rank so that you don't need to strip the R off later. We'll also derive a Read instance for Suit to make it easier to convert a string like "A" to a Suit value like A.
data Suit = A|B|C|D|E|F|G deriving (Show, Read, Eq)
data Rank = R1|R2|R3 deriving (Eq)
-- Define Show yourself so you don't constantly have to remove the `R`
instance Show Rank where
show R1 = "1"
show R2 = "2"
show R3 = "3"
data Card = Card Suit Rank deriving Eq
instance Show Card where
show (Card s r) = show s ++ show r
With that out of the way, we can define some parsers for each type.
-- Because oneOf will fail if you don't get one
-- of the valid suit characters, read [s] is guaranteed
-- to succeed. Using read eliminates the need for a
-- large case statement like in rank, below.
suit :: Parser Suit
suit = do
s <- oneOf "ABCDEF"
return $ read [s]
rank :: Parser Rank
rank = do
n <- oneOf "123"
return $ case n of
'1' -> R1
'2' -> R2
'3' -> R3
-- A Card parser just combines the Suit and Rank parsers
card :: Parser Card
card = Card <$> suit <*> rank
-- parse returns an Either ParseError Card value;
-- you can ignore the exact error if the parser fails
-- to return Nothing instead.
toCard :: String -> Maybe Card
toCard s = case parse card "" s of
Left _ -> Nothing
Right c -> Just c
oneOf is a predefined parser that consumes exactly one of the items in the given list.
parse takes three arguments:
A parser
A "source name" (only used for error message; you can use any string you like)
The string to parse

Creating Instance of Eq for custom data type in Haskell

I have made some custom Data types for number representation in Haskell, now I want to implement Eq instances for it, but I am somehow stuck. So I have already made:
data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg -- Pos fuer Positive, Neg fuer Negative
newtype Numeral = Num (Sign,Digits)
instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False
instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False
Now I want to check out the Sign in my custom type Numeral so I tried this:
instance (Eq Sign) => Eq (Numeral) where
(==) Num(x,_)== Num(y,_) = x==y
But I get this error: Parse error in pattern : (==)
Mostly putting what I've already written in the comments in a more fleshed out form:
There are a few problems with your code:
You have to indent the code under the instance declarations. That way you tell the compiler what code belongs to the instance declaration.
In the following line you are asking for a type class constraint on a concrete type (Eq Sign =>). This is not possible in standard Haskell and even if you were to follow the compiler instructions and enable the FlexibleInstances language extension it wouldn't make sense.
instance (Eq Sign) => Eq (Numeral) where
Type class constraints are only used for type variables. For example:
double :: Num a => a -> a
double x = x + x
Here we say, that the function double only works for all types that implement Num. double :: Num Int => Int -> Int on the other hand is redundant, because we already know, that Int has a Num instance. The same for Eq Sign.
For instances such constraints only make sense, if the type you are writing an instance for contains another polymorphic type. Fox example instance Ord a => Ord [a]. Here we would use the Ord instance of the elements of the list to lexiographically order lists.
You can define (==) either in infix or prefix form, but not both. So either (==) (Num (x,_)) (Num (y,_)) = x == y or Num (x,_) == Num (y,_) = x == y.
Newtyping tuples to create a product type is rather strange. Newtypes are usually used if you want to use the functionality that is already present for the more complex underlying type. However here that is not the case, you just want a normal product of Digits and Sign.
You are only comparing the Sign of the numbers. While technically a valid Eq instance, I think you also want to compare the digits of the number probably truncating leading zeros. In the code below I didn't truncate zeros though, to keep it simple.
data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg
data Numeral = Num Sign Digits
instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False
instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False
instance Eq Numeral where
Num s1 x1 == Num s2 x2 = s1 == s2 && x1 == x2

Haskell Double String Concatenation

I am starting out in Haskell and have created the following two functions:
calcBmi :: ( RealFloat a ) => a -> a -> a -- Accepts two and returns one 'RealFloat' number.
calcBmi w h = w / h ^ (2 :: Integer) -- Stores argument one and two in w and h respectively and evaluates
outputBmi :: (RealFloat a) => a -> a -> String -- Accepts two RealFloats and returns string
outputBmi weight height = let bmi = calcBmi weight height in "Your BMI was calculated to " ++ bmi
When I attempt to compile this code I get the following exception
Couldn't match expected type '[Char]' with actual type 'a'
In the second argument of '(++)', namely 'bmi'
I am stumped as to what the error even means, nevermind how to fix the code to compile correctly. I can only assume it has something to do with the type of the 'bmi' variable.
If someone could help a beginner out that would be much appreciated. If you see other issues in the code (or if I am using the wrong terminology) feel free to let me know.
The variable is not a string, and therefore can not be used by the (++) function. Usually, you can however convert it to a String using show, however, your type doesn't specify that a is an instance of class Show, so you may have to add this, or even just specify the type directly (ie- Float)
For instance, you can change the type of calcBmi
calcBmi :: Float->Float->Float
or
calcBmi :: (RealFloat a, Show a)=>a->a->a
Then you can create a string as follows
"Your BMI was calculated to " ++ show bmi

Create a type that can contain an int and a string in either order

I'm following this introduction to Haskell, and this particular place (user defined types 2.2) I'm finding particularly obscure. To the point, I don't even understand what part of it is code, and what part is the thoughts of the author. (What is Pt - it is never defined anywhere?). Needless to say, I can't execute / compile it.
As an example that would make it easier for me to understand, I wanted to define a type, which is a pair of an Integer and a String, or a String and an Integer, but nothing else.
The theoretical function that would use it would look like so:
combine :: StringIntPair -> String
combine a b = (show a) ++ b
combine a b = a ++ (show b)
If you need a working code, that does the same, here's CL code for doing it:
(defgeneric combine (a b)
(:documentation "Combines strings and integers"))
(defmethod combine ((a string) (b integer))
(concatenate 'string a (write-to-string b)))
(defmethod combine ((a integer) (b string))
(concatenate 'string (write-to-string a) b))
(combine 100 "500")
Here's one way to define the datatype:
data StringIntPair = StringInt String Int |
IntString Int String
deriving (Show, Eq, Ord)
Note that I've defined two constructors for type StringIntPair, and they are StringInt and IntString.
Now in the definition of combine:
combine :: StringIntPair -> String
combine (StringInt s i) = s ++ (show i)
combine (IntString i s) = (show i) ++ s
I'm using pattern matching to match the constructors and select the correct behavior.
Here are some examples of usage:
*Main> let y = StringInt "abc" 123
*Main> let z = IntString 789 "a string"
*Main> combine y
"abc123"
*Main> combine z
"789a string"
*Main> :t y
y :: StringIntPair
*Main> :t z
z :: StringIntPair
A few things to note about the examples:
StringIntPair is a type; doing :t <expression> in the interpreter shows the type of an expression
StringInt and IntString are constructors of the same type
the vertical bar (|) separates constructors
a well-written function should match each constructor of its argument's types; that's why I've written combine with two patterns, one for each constructor
data StringIntPair = StringInt String Int
| IntString Int String
combine :: StringIntPair -> String
combine (StringInt s i) = s ++ (show i)
combine (IntString i s) = (show i) ++ s
So it can be used like that:
> combine $ StringInt "asdf" 3
"asdf3"
> combine $ IntString 4 "fasdf"
"4fasdf"
Since Haskell is strongly typed, you always know what type a variable has. Additionally, you will never know more. For instance, consider the function length that calculates the length of a list. It has the type:
length :: [a] -> Int
That is, it takes a list of arbitrary a (although all elements have the same type) and returns and Int. The function may never look inside one of the lists node and inspect what is stored in there, since it hasn't and can't get any informations about what type that stuff stored has. This makes Haskell pretty efficient, since, as opposed to typical OOP languages such as Java, no type information has to be stored at runtime.
To make it possible to have different types of variables in one parameter, one can use an Algebraic Data Type (ADT). One, that stores either a String and an Int or an Int and a String can be defined as:
data StringIntPair = StringInt String Int
| IntString Int String
You can find out about which of the two is taken by pattern matching on the parameter. (Notice that you have only one, since both the string and the in are encapsulated in an ADT):
combine :: StringIntPair -> String
combine (StringInt str int) = str ++ show int
combine (IntString int str) = show int ++ str

Resources