Record syntax default value for accessor - haskell

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

Related

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

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

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

Haskell's algebraic data types: "pseudo-extend"

I am learning about Algebraic DTs in haskell. What I would like to do is create a new ADT that kind of "extends" an existing one. I cannot find how to express what I would like, can someone sugest an alternative pattern or sugest a solution. I want them to be distinct types, but copying and pasting just seams like a silly solution. The code below best describes what I am seeking.
data Power =
Abkhazia |
-- A whole bunch of World powers and semi-powers
Transnistria
deriving (Eq, Show)
data Country =
--Everything in Power |
Netural |
Water
deriving (Eq, Show)
Edit: I think It need a little clarification... I want to be able to do this (in ghci)
let a = Abkhazia :: Country
and not
let a = Power Abkhazia :: Country
You need to represent them as a tree:
data Power
= Abkhazia
| Transnistria
deriving (Eq, Show)
data Country
= Powers Power -- holds values of type `Power`
| Netural -- extended with other values.
| Water
deriving (Eq, Show)
Edit: your extension to the question makes this a bit simpler: both the Country and Power types share some common behavior as "countries". This suggests you use the open, extensible type class feature of Haskell to given common behaviors to the data type. E.g.
data Power = Abkhazia | Transistria
data Countries = Neutral | Water
then, a type class for things both Power and Countries share:
class Countrylike a where
landarea :: a -> Int -- and other things country-like entities share
instance Countrylike Power where
landarea Abkhazia = 10
landarea Transistria = 20
instance Countrylike Countries where
landarea Neutral = 50
landarea Water = 0
then you can use landarea cleanly on either powers or countries. And you can extend it to new types in the future by adding more instances.
{-# LANGUAGE GADTs, StandaloneDeriving #-}
data POWER
data COUNTRY
data CountryLike a where
Abkhazia :: CountryLike a
Transnistria :: CountryLike a
Netural :: CountryLike COUNTRY
Water :: CountryLike COUNTRY
deriving instance Show (CountryLike a)
deriving instance Eq (CountryLike a)
type Power = CountryLike POWER
type Country = CountryLike COUNTRY
foo :: Power
foo = Abkhazia
bar :: Country
bar = Abkhazia
baz :: Country
baz = Netural
Edit: An alternative would be type Power = forall a. CountryLike a (Advantage: Makes Power a subtype of Country. Disadvantage: This would make e.g. Power -> Int a higher-rank type, which tend to be annoying (type inference etc.))

Haskell data type

Let's say that I have a type like this (that works):
data WAE = Num Float
| Id String
| With [(String, WAE)] WAE -- This works, but I want to define it as below
deriving(Eq, Read, Show)
I want a type like this (doesn't work):
data WAE = Num Float
| Id String
| With [(Id, WAE)] WAE -- This doesn't work ("Id not in scope")
deriving(Eq, Read, Show)
Why can't I do that in Haskell? Any ideas in achieveing a similar effect?
In Haskell, there are two distinct namespaces. One for values, and one for types. Data constructors such as Id live in the value namespace, whereas type constructors such as String, as well as classes live in the type namespace. This is OK because there is no context where both would be allowed.
In the definition of a data type, the two namespaces live side by side, as you're defining a both a new type constructor and several new data constructors, while referring to existing type constructors.
data WAE = Num Float
| Id String
| With [(String, WAE)] WAE
deriving(Eq, Read, Show)
Here, WAE, Float, String, (,), [], Eq, Read and Show are all names in the world of types, whereas Num, Id and With are names in the world of values. Mixing them does not make any sense, and this is why Id is not in scope in your second piece of code, as you are in a type context, and there is no type-level thing called Id.
It's not 100% clear from your question what you were trying to do, but I suspect it might be something like this:
type Id = String -- Or perhaps a newtype
data WAE = Num Float
| Id Id
| With [(Id, WAE)] WAE
deriving(Eq, Read, Show)
Note that because the namespaces are distinct, it's perfectly fine to have something called Id in both.
Based on your question, I'm not entirely sure what you are trying to accomplish. Here are two possibilities that are possible with Haskell's type-system.
data WAE = Num Float
| Id String
| With [(WAE, WAE)] WAE
deriving (Eq, Read, Show)
I'm not sure this is what you want, however, because it allows for more than just an id in the first portion of the pair.
Another possibility is to create a new type (or alias) for the id, like so:
data MyId = MyId String deriving (Eq, Read, Show)
data WAE = Num MyId Float
| Id MyId
| With [(MyId, WAE)] WAE
deriving (Eq, Read, Show)
Note that MyId could also be created with either newtype or type, each giving a slightly different meaning.
You cannot, however use Id as it is a data-constructor, where a type is expected.
Here:
| With [(Id, WAE)] WAE
you are using a data constructor Id in a context where a type is expected. The type of Id is WAE, so if you change this line to:
| With [(WAE, WAE)] WAE
it will compile, but the result is probably not what you want.
If you just want to show that the string in question is an identifier semantically, you can use a type alias:
type Id = String
data WAE = Num Float
| Id Id
| With [(Id, WAE)] WAE
deriving(Eq, Read, Show)

Creating convenient type

I am beginning with Haskell. I have a situation where it is convenient to work the following type synonyms:
type Adult = Int
type Youth = Int
However I can not overload functions on Adult and Youth even if they had been synonyms for different types so have to have two seperate versions of functions eg. doSomethingForAdult and doSomethingForYouth , so next I tried
data Person = Adult Int | Youth Int
Then I can pattern match and use a single version of functions,
but then I loose the option of using the Adult and Youth as types in functions declarations which is convenient. Is there a middle way ? I looked at Either, but from the description in tutorials it seems this would be misuse ? Something similar to a small type hierarchy with Person at the root and Youth and Adult derived and still being synonyms for Int would be perfect but I can not figure out how.
I don't see how that would be a misuse of Either. Just as (,) is a generic product type, Either is perfectly acceptable as a generic sum type, i.e. anything of the form:
data T = T1 A | T2 B C
...can be thought of algebraically as A + (B * C), which is equivalent to Either A (B, C).
On the other hand, if you want to distinguish between Adult and Youth, using synonyms for the same actual type can be counterproductive; they're just transparent aliases. An alternate approach would be to use newtypes, like this:
newtype Adult = Adult Int deriving (Eq, Ord, Show, Read, Num)
newtype Youth = Youth Int deriving (Eq, Ord, Show, Read, Num)
Adjust the deriving clause to taste; I added Num here because the underlying type is numeric, but if all you want is a unique identifier then adding or multiplying them doesn't make sense. At this point you can then use a sum type for Person if you like, or define a type class to get proper overloading:
class Person a where
-- (etc...)
instance Person Adult where -- ...
instance Person Youth where -- ...
Any functions defined in Person are then effectively overloaded on Adult and Youth, letting you dispatch based on type the way "overloaded" functions in other languages do.
Are you wanting a typeclass?
data Adult = Adult Int
data Youth = Youth Int
class Person a where
doSomething :: a -> b
instance Person Adult where
doSomething (Adult i) = ...
instance Person Youth where
doSomething (Youth i) = ...
This is the typical manner of overloading function in Haskell. The typeclass, Person, has a single function, doSomething :: a -> b. Each data type you want to be an instance of Person can have its own, separate, implementation. If you want the underlying implementation to be the same then just use another function, doSomethingGlobal :: Int -> b and let each instance equal this new function.
You can have both:
type Adult = Int
type Youth = Int
data Person = Adult Adult | Youth Youth
Data constructors are in a separate namespace from types so there is no conflict here.
I would suggest to just add the type synonym
type Person = Int
and you are able to give types to functions that work both, for Adults abd Youth, like
doSomething :: Person -> ...
(and you keep the possibility to use Adult and Youth in other type signatures)
I suggest to make Person polymorphic:
data Person a = Person a Int
With this definition you can write general functions on Person level that don't care about the concrete value of a:
getInt :: Person a -> Int
getInt (Person _ i) = i
incInt :: Person a -> Person a
incInt (Person p i) = Person p (inc i)
Then you can define "tags" to substantiate a Person:
data Adult = Adult
data Youth = Youth
Now you can write functions for a specific type of Person
rock :: Person Youth -> String
rock (Person Youth k) = "I rock until " ++ show k ++ " in the morning!!!"

Resources