How to write customised show function in Haskell - haskell

I am defining a Octave type:
data Octave = 1 | 2 | 3
deriving (Show, Read, Ord, Enum)
Since '1' is not valid for data constructor identifiers, I have to do it like so:
data Octave = O1 | O2 | O3
deriving (Show, Eq, Read, Ord, Enum)
Now, if I show Octave O1 it shows "O1" which is not exactly what I want. I want the result to be "1". I know we can customise our Show behaviour like this:
instance Show Blabla where
show (Blabla ints chars list num) =
"integers = " ++ show ints ++ "\n"
But the problem is that I am using enumeration type which means it doesn't have a value except its identifier name 'O1'. How can I access that in Haskell?
Another question: How can I read it back?
read "O1" :: Octave works, but I want read "1" :: Octave
instance Read Octave where
read "1" = O1
read "2" = O2
read "3" = O3
This doesn't work: "read is not a (visible) method of class Read".

Taking advantage of Octave's Enum instance and using the Show and Read instances for Int we can implement showing and reading like this:
data Octave = O1 | O2 | O3 deriving (Eq, Ord, Enum)
instance Show Octave where
show o = show (fromEnum o + 1)
instance Read Octave where
readsPrec prec = map (\(n,s) -> (toEnum (n - 1), s)) . readsPrec prec
I.e. fromEnum and toEnum convert between octaves and ints so that O1 <-> 0 and O2 <-> 1, so we have to adjust by one in both reading and writing.

Seems like all you need is this, right?
instance Show Octave where
show O1 = "1"
show O2 = "2"
show O3 = "3"
Define show with three clauses, and let the pattern matcher figure it out.

Here's a different approach:
data Octave_ = O1 | O2 | O3 deriving (Show, Eq, Read, Ord, Enum)
newtype Octave = O { unO :: Octave_ } deriving (Eq, Ord, Enum)
instance Show Octave where
show = tail . show . unO
Depending on what you are doing this could be good or bad.

You can always use existing instances for Int, like so:
data Octave = O1 | O2 | O3 deriving (Enum,Bounded)
instance Show Octave where
show = show . (+1) . fromEnum
instance Read Octave where
readsPrec pr = map (\ (int,str) -> ((toEnum (int-1)),str) . readsPrec pr
This correctly renders O1..O3 as 1..3 and reads them back. The only pitfall is when trying to read a different integer, like 4:
*** Exception: toEnum{Octave}: tag (3) is outside of enumerations'range (0,2)
This could be fixed by writing more code and checking for valid values in readsPred.

It looks like you want to access the identifier name. you could use something like template haskell to do it but this is a terrible idea.
Actually, the fist bad idea is probably to rely on show. Show class is traditionally use to "serialize" data, while Read class will de-serialize them. If you want to pretty print the output, you'd better write your own Octave -> String function. To do so, you could rely on the result of show (and truncate the result). However, the most efficient solution might be to encode it directly, as proposed by amalloy.

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

How to create data out of two other data?

I am trying to make a Card data type. The problem I am having is that I currently have the cards set up as a "CardValue" and a "Suit" data type which are each separate, and then I was trying to make a "Card" data type that is essentially just (CardValue, Suit). I need the "Card" data to be data and not type so that I can make it an instance of show, but I do not know if this is possible the way I am doing this. Is there a way to make a single Card data that would have every possible card in a deck without going "data Card = AceHeart | AceSpade | AceClub ... etc."?
Here is what I have so far:
data CardValue = Ace | Two | Three
| Four | Five | Six
| Seven | Eight | Nine
| Ten | Jack | Queen
| King deriving (Bounded, Enum, Show, Eq, Ord)
data Suit = Clubs | Spades | Hearts | Diamonds deriving (Show, Eq)
data Card = (CardValue, Suit)
instance Show Card where
show (v, s) = show v ++ " of " ++ show s
Yes, you just got the syntax slightly wrong.
Just write
data Card = Card CardValue Suit
instead (note that the second "Card" in the above code could also be called something else; The left side names the type, the right side is a name for values of type card), and then you can write your show instance as
instance Show Card where
show (Card v s) = show v ++ " of " ++ show s
Since you use data you define a new data type. You thus will need to specify a data constructor. You can not use the tuple data constructor (,) here.
You thus can define:
data Card = Card CardValue Suit
Then you can for example implement an instance of Show:
instance Show Card where
show (Card v s) = show v ++ " of " ++ show s
That being said, Show is usually supposed to generate output that is Haskell code (so you can for example inject it back in the interpreter).
It might be better to define a class:
class Representable a where
repr :: a -> String
and thus implement this for Card as:
instance Representable Card where
repr (Card v s) = show v ++ " of " ++ show s

haskell writing constructors that do work in them

i have a few questions
Im writing this constructor called rope which i have like this
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
deriving Show
First off when i make a TextRope like this
*Main> let s =TextRope "why"
*Main> s
TextRope {ropeText = "why"}
*Main>
when i do s i want to just get the string of the constructor which is why and im not really sure about that.
Also curious about concat and sub constructors. Specifically it seems like to me you are calling these two constructors there is things happening, you are returning the result of concatenating rope 1 and rope 2 together, im not sure how to describe that in this language, you are defining the data structure but somehow the return of that is a result that has to be calculated by the structure
Here are some examples of what how these functions work
> let tr = TextRope "Hello,"
> let sr = TextRope " world!"
> let hw = ConcatRope tr sr
> let ow = SubRope hw 4 4
> tr
Hello,
> sr
world!
> hw
Hello, world!
Sort of confused overall, new to haskell constructors and datatypes, so some pointers would be helpful (not c pointers though!)
Data constructors never do work. They only hold the data you pass into them. If you want work to be done, you should define what are called smart constructors, which are just functions that perform some operation before passing it to the actual constructor. An example might be
data Fraction = Fraction
{ numerator :: Int
, denominator :: Int
} deriving (Eq)
(%) :: Int -> Int -> Fraction
x % y =
let (a, b) = reduce x y
in Fraction a b
-- Reduces a fraction to it's simplest terms
reduce :: Int -> Int -> (Int, Int)
reduce num den = undefined
Here you wouldn't export the Fraction constructor from your module, just the % function that constructs one in the most reduced form.
The other problem you have is that you want your constructors to print out differently. You can achieve this by not deriving Show. However, I will warn that the Haskell convention is that show . read = read . show = id, which wouldn't hold for what you want to do. This isn't a strict convention, though, and there's nothing stopping you from doing something like:
data Rope = <your implementation minus the deriving Show bit>
instance Show Rope where
show (TextRope t) = t
show (ConcatRope r1 r2) = show r1 ++ show r2
show (SubRope r starting ending) = <exercise left to reader>
As an aside, I would recommend against having a sum type of records with different field names, this can lead to problems where your program type-checks but contains errors that can be caught at compile time if written differently. For example, what would happen if you had the code
> ropeText (ConcatRope (TextRope "Hello, ") (TextRope "world!"))
This would cause an error and crash your program! Instead, it looks like you just want a Rope type with concat and subRope functions, so you could implement it very simply as
data Rope = Rope String deriving (Eq)
concatRope :: Rope -> Rope -> Rope
concatRope (Rope r1) (Rope r2) = Rope (r1 ++ r2)
-- Why use Integer instead of Int? You might find it's easier to implement this function
subRope :: Rope -> Integer -> Integer -> Rope
subRope (Rope r) start end = Rope $ substr start end r
where substr s e text = <exercise left to reader>
Now there's absolutely no way to have an illegal rope operation, the only difference is now you have to use concatRope in place of ConcatRope and subRope in place of SubRope. You're guaranteed that these functions will do what you want, you don't have some complicated type that doesn't help you anyway.
if you don't implement your own show (not with auto-deriving) you will have a harder time getting what you want.
But if you do it's kindof easy:
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
instance Show Rope where
show (TextRope s) = s
show (ConcatRope a b) = show a ++ show b
I'm sure you'll find the implementation for the SubRope case youself ;)
Your example code and your example interactive results don't match. This is how you've defined Rope:
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
deriving Show
The deriving Show part is key there; we'll see how.
Later you show this example output:
> let tr = TextRope "Hello,"
> let sr = TextRope " world!"
> let hw = ConcatRope tr sr
> hw
Hello, world!
With the code that I just showed, actually, what you'll see is the following:
> hw
ConcatRope { rope1 = TextRope "Hello,", rope2 = TextRope " world!" }
The only way we could get the output that you describe is if we got rid of the deriving Show clause in your definition of Rope, and wrote this:
instance Show Rope where
show (TextRope text) = text
show (ConcatRope r1 r2) = show r1 ++ show r2
show (SubRope rope start end) = ...

haskell type,new type or data for only an upper case char

If i want to make a String but holds only an uppercase character. I know that String is a [Char]. I have tried something like type a = ['A'..'Z'] but it did not work any help?
What you're wanting is dependent types, which Haskell doesn't have. Dependent types are those that depend on values, so using dependent types you could encode at the type level a vector with length 5 as
only5 :: Vector 5 a -> Vector 10 a
only5 vec = concatenate vec vec
Again, Haskell does not have dependent types, but languages like Agda, Coq and Idris do support them. Instead, you could just use a "smart constructor"
module MyModule
( Upper -- export type only, not constructor
, mkUpper -- export the smart constructor
) where
import Data.Char (isUpper)
newtype Upper = Upper String deriving (Eq, Show, Read, Ord)
mkUpper :: String -> Maybe Upper
mkUpper s = if all isUpper s then Just (Upper s) else Nothing
Here the constructor Upper is not exported, just the type, and then users of this module have to use the mkUpper function that safely rejects non-uppercase strings.
For clarification, and to show how awesome dependent types can be, consider the mysterious concatenate function from above. If I were to define this with dependent types, it would actually look something like
concatenate :: Vector n a -> Vector m a -> Vector (n + m) a
concatenate v1 v2 = undefined
Wait, what's arithmetic doing in a type signature? It's actually performing type-system level computations on the values that this type is dependent on. This removes a lot of potential boilerplate in Haskell, and it makes guarantees at compilation time that, e.g., arrays can't have negative length.
Most desires for dependent types can be filled either using smart constructors (see bheklilr's answer), generating Haskell from an external tool (Coq, Isabelle, Inch, etc), or using an exact representation. You probably want the first solution.
To exactly represent just the capitals then you could write a data type that includes a constructor for each letter and conversion to/from strings:
data Capital = CA | CB | CC | CD | CE | CF | CG | CH | CI | CJ | CK | CL | CM | CN | CO | CP | CQ | CR | CS | CT | CU | CV | CW | CX | CY | CZ deriving (Eq, Ord, Enum)
toString :: [Capital] -> String
toString = map (toEnum . (+ (fromEnum 'A')) . fromEnum)
You can even go a step further and allow conversion from string literals, "Anything in quotes", to a type [Capitals] by using the OverloadedStrings extension. Just add to the top of your file {-# LANGUAGE OverloadedStrings, FlexibleInstances #-}, be sure to import Data.String and write the instance:
type Capitals = [Capital]
instance IsString Capitals where
fromString = map (toEnum . (subtract (fromEnum 'A')) . fromEnum) . filter (\x -> 'A' <= x && x <= 'Z')
After that, you can type capitals all you want!
*Main> toString ("jfoeaFJOEW" :: Capitals)
"FJOEW"
*Main>
bheklilr is correct but perhaps for your purposes the following could be OK:
import Data.Char(toUpper)
newtype UpperChar = UpperChar Char
deriving (Show)
upperchar :: Char -> UpperChar
upperchar = UpperChar. toUpper
You can alternatively make UpperChar an alias of Char (use type instead of newtype) which would allow you to forms lists of both Char and UpperChar. The problem with an alias, however, is that you could feed a Char into a function expecting an UpperChar...
One way to do something similar which will work well for the Latin script of your choice but not so well as a fully general solution is to use a custom type to represent upper case letters. Something like this should do the trick:
data UpperChar = A|B|C|D| (fill in the rest) | Y | Z deriving (Enum, Eq, Ord, Show)
newtype UpperString = UpperString [UpperChar]
instance Show UpperString
show (UpperString s) = map show s
The members of this type are not Haskell Strings, but you can convert between them as needed.

How to create a type bounded within a certain range

I would like to create a new integral type which is bounded to a certain range. I have tried:
data PitchClass = PC Int deriving (Ord, Eq, Show)
instance Bounded PitchClass where
minBound = PC 0
maxBound = PC 11
However, what I want is something that will fail if something like
PC 12
or
PC (-1)
is attempted.
Is the general approach for a situation in which you wish to place constraints on creating new types one in which the value constructors are not exported from the module, but rather functions which return instances of the type and which perform constraint checks are exported?
Yes, not exporting the data constructor from the module is the way to go.
Instead, you export a function which does the checking as you said. This is often called a smart constructor.
An alternate solution for cases where the number of total values is this small is to simply enumerate the possible constructors.
data PitchClass = A | Bb | B | C | Db | D | Eb | E | F | Gb | G | Ab
deriving (Eq, Ord, Bounded, Show, Read)
There are half a dozen different hacks you can try from here to make it more convenient in various ways; for example, you can derive Enum to get toEnum . fromEnum = id (and toEnum (-1) = {- an exception -}), or you can write a custom Integral instance to get 0 = A (and your choice of behavior for -1).

Resources