20-CS-4003-001 Organization of Programming Languages Fall 2017

Lambda calculus, Type theory, Formal semantics, Program analysis

Prev     Next     All lectures           Code

The Type System

{- data Bool = True | False deriving (Show) -}

{- data Maybe a =
     Nothing | Just a deriving (Show) -}

data Color = 
     Red | Green | Blue | Indigo | Violet 
     deriving (Ord, Eq, Show)

data Point a = Pt a a

data Tree a =
     | Node a (Tree a) (Tree a) 
     | Leaf a deriving (Show, Read, Eq)

data Either a b =
     Left a | Right b 
     deriving (Eq, Ord, Read, Show)  

data Shape =
       Circle Float Float Float 
     | Rectangle Float Float Float Float
     | Triangle Int Int

area (Circle x y r) = pi*r^2
area (Rectangle x y w h) = w*h
area (Triangle b h) = 
  (fromIntegral b)*(fromIntegral h)/2

v1 = area (Circle 3 4 5)
v2 = area (Rectangle 1 2 3 4)
v3 = area (Triangle 5 7)

v4 = Just "a string"
v5 x y = Just x+y

v6 = Main.Right 'a'

treeInsert x Empty = Leaf x
treeInsert x (Leaf a)
   | x == a = Leaf x
   | x < a
     = Node a (treeInsert x Empty) Empty
   | x > a
     = Node a Empty (treeInsert x Empty)
treeInsert x (Node a left right)
   | x == a = Node x left right
   | x < a
     = Node a (treeInsert x left) right
   | x > a
     = Node a left (treeInsert x right)

inTree x EmptyTree = False
inTree x (Leaf a) 
   | x == a = True
   | otherwise = False
inTree x (Node a left right)
   | x == a = True
   | x < a  = inTree x left
   | x > a  = inTree x right

v7 = treeInsert Green Empty
v8 = treeInsert Indigo v7
v9 = treeInsert Blue v8
v10 = treeInsert Red v9
v11 = treeInsert Violet v10

v12 = inTree Violet v11
v13 = inTree Violet v10
  -   Haskell's type system has been engineered to be both flexible, as a logic for property verification, and powerful.

Haskell's type system has been developed to encourage a relatively flexible, expressive static checking discipline, that enable powerful new classes of compile-time verification.

Haskell/GHC provides a logic that is both powerful and designed to encourage type level programming.

See the haskell review for a list of built-in data types and type classes. Users may define types according to the following syntax:

 data T u1 ... un = 
    C1 t1,1 ... t1,k1 | ... | Cn tn,1 ... tn,kn

  T is a type constructor
  ui are type variables
  Ci are data constructors
  ti,j are constituent types

The presence of ui imply the type is polymorphic (it may be instantiated by substituting different types for ui). Simple examples are shown at the top to the left. Bool and Color are nullary type constructors because they have no arguments. Bool redefines an existing data type which is OK except that using True or False will be ambiguous unless the type used is specified, for example with Main.True. True, False, Red, etc are nullary data constructors. Bool and Color are enumerations because all of their data constructors are nullary. Color objects may be compared due to the deriving (Ord, Eq) extension to the type definition. Thus:

 *Main> Red < Green
 *Main> Violet < Blue
 *Main> Indigo == Indigo
Point is a product or tuple type constructor because it has only one constructor. Tree is a union of types, often called an algebraic data type. Maybe will be important to support polymorphism.

Consider the Shape type which is the union of a Circle type, defined by a 2-D coordinate center plus radius, a Rectangle type, defined by an upper left 2-D coordinate corner plus width and height, and a Triangle type defined by a base and height. Observe that the constructors Circle and Rectangle take Float arguments and the the Triangle constructor takes Int arguments. Do this:

 *Main> :t Circle
 Circle :: Float -> Float -> Float -> Shape
 *Main> :t Triangle
 Triangle :: Int -> Int -> Shape
The function area, to the left, is defined for all shapes.
 *Main> v1
 *Main> v2
 *Main> v3

Due to the type variable in the type constructor Maybe, Main.Just is the polymorphic type a -> Main.Maybe a. Since Maybe is redefined here, Main.Just must be used because Just is defined in Prelude and the prefix Main. is necessary to prevent ambiguity.

 *Main> v4
 Just "a string"
 *Main> :t v4
 v4 :: Maybe [Char]
 *Main> :t v5
 v5::Num (Maybe a) => a -> Maybe a -> Maybe a
Without deriving (Show) in the definition of Maybe we would get:
 No instance for (Show (Main.Maybe [Char]))
    arising from a use of print'
 *Main> Main.Right 'a'
 v6 :: Main.Either a Char
when trying to display the value of v4.

The functions treeInsert and inTree build a binary search tree and conduct a search for an element in a binary search tree, respectively, based on a recursive binary search tree data type called Tree. The type of treeInsert is

 treeInsert :: Ord a => a -> Tree a -> Tree a
Therefore, Nodes can be Colors, Integers and other types in the class Ord.
 *Main> v7
 Leaf Green
 *Main> v8
 Node Green Empty (Leaf Indigo)
 *Main> v9
 Node Green 
   Empty (Node Indigo 
            (Leaf Blue) Empty)
 *Main> v10
 Node Green 
   (Leaf Red) (Node Indigo 
                 (Leaf Blue) Empty)
 *Main> v11
 Node Green 
   (Leaf Red) (Node Indigo
                 (Leaf Blue) (Leaf Violet))
 *Main> v12
 *Main> v13