How to create a type bounded within a certain range - haskell

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

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

Algebraic data type (intended) name collision.. how to?

I had the idea to implement my own little music theory module in Haskell.
Starting with notes (Note) makes sense and right there and then I ran into this nasty syntactic problem, I have no idea how real Haskellers handle it.
data Note = Sharp NoteS | Flat NoteF deriving (Show)
data NoteS =
C | SC | D | SD | E | F | SF | G | SG | B
deriving (Ord,Show,Eq)
data NoteF =
C | FD | D | FE | E | F | FG | G | FB | B
deriving (Ord,Show,Eq)
instance Eq Note where
(==) (NoteS n1) (NoteS n2) = n1 == n2
(==) (NoteF n1) (NoteF n2) = n1 == n2
(==) (NoteS n1) (NoteF n2) = ???
(==) (NoteF n1) (NoteS n2) = ???
...
flatToSharp :: Note -> NoteS
sharpToFlat :: Note -> NoteF
As most might know, a sharp C and a flat D are synonymous in general but sometimes it is prefered to use one or the other depending on context. So I hoped to use the fact that both NoteS and NoteF are instances of Ord (e.g. for interval calculation). But in both representations, the plain notes (C,D,E,F...) have the same names in both types.
Now I could think of ways to "hack" around this syntactic problem. But it would either have ugly syntactic implications or run time implications (e.g. use Strings instead of a types, lots of testing and error checking,...).
So here is my question to Haskell professionals... How would I do it in the spirit of my idea without too many concessions to this "namespace" problem of Haskell?
I tried {-# LANGUAGE DuplicateRecordFields #-} but it does not help with unions, obviously.
If you must keep the data representation as you have it there, the standard namespacing mechanism in Haskell is modules. So you could write
module Sharps where data NoteS = ...
module Flats where data NoteF = ...
module Main where
import Sharps as S
import Flats as F
(Of course, don't forget that for GHC, each module must go in its own file with an appropriate filename.) Then, in Main, you could refer to Sharps.C or S.C to get the NoteS constructor, and Flats.C or F.C to get the NoteF constructor.
But may I propose a different solution? How about naming the natural notes, and simply having a type that records how sharp or flat you've gone from there? After all, you're going to want to handle double sharps and double flats eventually, I'm sure. So:
data Natural = A | B | C | D | E | F | G
data Note = Note
{ natural :: Natural
, offset :: Int -- positive for sharp, negative for flat, say
}
(There are many other data representation choices you could make as well.)
Another idea is to use a pattern synonym. You can have a single type representing notes, and synonyms to rename some of them.
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#pattern-synonyms
{-# LANGUAGE PatternSynonym #-}
data Note = C | SC | D | SD | E | F | SF | G | SG | B
pattern FD = SC
pattern FE = SD
pattern FG = SF
pattern FB = SG

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 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.

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.

Resources