16 Nov

Simple types

Work like an alias for an existing type

type Temperature = Float

Declaring objects of the new type

summer :: Temperature
summer = 30

Defining functions using the new type

isCold :: Temperature -> Bool
isCold temp = (temp < 10)

> isCold summer
False

The defined function works for Temperature objects as well as the aliased type, plain Float

winter :: Float
winter = 4.5

> isCold winter
True

Algebraic data types

Similar to enum in other languages

data State = Liquid | Solid | Gas  -- matter can be in one of the 3 states

Declaring objects

deskState :: State
deskState = Solid

Comparing

eqState :: State -> State -> Bool
eqState Liquid Liquid = True
eqState Solid  Solid  = True
eqState Gas    Gas    = True
eqState _      _      = False  -- any other combination is not equal

Representing/printing, similar to the toString() method in other languages

showState :: State -> String
showState Liquid = "Liquid"
showState Solid  = "Solid"
showState Gas    = "Gas"

Data types with arguments

type Width  = Float
type Height = Float
type Radius = Float

data Shape = Circle Radius      -- a shape is either a circle (which has radius)
           | Rect Width Height  -- or a rectangle (which has width and height)

Declaring objects

deskShape :: Shape
deskShape = Rect 10 20.5  -- a rectangular desk

Defining functions, using pattern matching

area :: Shape -> Float
area (Circle r) = pi * r^2
area (Rect w h) = w * h

> area deskShape
205.0  -- 10 * 20.5

Overload the show function for a Shape

instance Show Shape where
  show (Circle r) = "Circle " ++ show r
  show (Rect w h) = "Rectangle " ++ show w ++ " x " ++ show h

> deskShape
"Rectangle 10.0 x 20.5"

Overload the == operator for two Shapes

instance Eq Shape where
  (Circle r1)  == (Circle r2)   = (r1 == r2)  -- equal only if they have the same radius
  (Rect w1 h1) == (Rect w2 h2)  = (w1 == w2) && (h1 == h2)  -- if their dimensions match
  shape1 == shape2              =  False  -- anything else is not equal

> deskShape == (Rect 5 5)
False

Projections

type Name = String
type Age = Int
data Person = Person Name Age

john :: Person
john = Person "John" 25

Extract a certain field from an object, similar to person.getAge() in other languages

ageOf :: Person -> Age
ageOf (Person name age) = age

> ageOf john
25

Using it

isOverage :: Person -> Bool
isOverage pers = (ageOf pers > 18)

> isOverage john
True

Entries

Similar to class definitions in other languages

data Superhero = Superhero { name  :: Name
                           , power :: String
                           } deriving (Show, Eq)  -- default implementation

Declaring objects can be done in either way

superman, batman :: Superhero
superman = Superhero "Superman" "flying"
batman = Superhero { name = "Batman", power = "rich" }  -- alternative declaration

Using deriving (Show, Eq) gives the default implementation for show and ==

> superman
Superhero {name = "Superman", power = "flying"}  -- default representation

> superman == batman  -- element-wise comparison
False

Projections are implicit

hiddenIdentity :: Superhero -> Name
hiddenIdentity hero = reverse (name hero)  -- like hero.name in other languages

> hiddenIdentity batman
"namtaB"

Updating fields

depower :: Superhero -> Superhero
depower hero = hero { power = "none"}  -- update the `power` field

> depower superman
Superhero {name = "Superman", power = "none"}