Programming Languages
Typing Systems with Haskell
Jim Posen  ECE/CS 2014
Type Systems
 A type system is the model a programming language uses to assign types to values or variables
 Static vs dynamic typing
 Strong vs weak typing
 Type safety properties
Static vs dynamic type checking

Are the types known without running the program?
 Type checkers perform static analysis
 Are the types known during compilation?
 Do variables have types?
 Languages may have optional type declarations
Staticly typed languages
 Java
 C/C++
 SML (functional language)
Dynamicly typed languages
Hybrids

Common Lisp
 Dynamic by default with optional type declarations
Strong vs weak typing
 Do values/objects have types?
 Higher standard of type safety
 Weakly typed languages have less type safety
 Not as clear cut as static/dynamic type checking

I know it when I see it
Strongly typed languages

Java
 ints can be added to Strings
 Is this an exception?

Python

Racket
 Rationals vs fixnums vs booleans vs symbols
 Weak languages often have more unexpected behavior
Typing Chart

Strong

Weak

Static

Java 
C 
Dynamic

Python 
JavaScript 
Back to Haskell
Prelude> "hello " ++ "world"
"hello world"
Prelude> "hello " ++ True
:9:13:
Couldn't match expected type `[Char]' with actual type `Bool'
In the second argument of `(++)', namely `True'
In the expression: "hello " ++ True
In an equation for `it': it = "hello " ++ True
OK, there is type safety, so Haskell must be strongly typed
 The above code won’t even compile
 Haskell is staticly typed
Type inference

Haskell
infers
the types of variables
 If variable types can’t be inferred, you will get a compilation error
 Type declarations can be used to remove ambiguity
 By convention, functions types are declared
Haskell types
 Use :t to determine type
 Bool, Char, Int, Float, Integer, Double are some basic types

[] denotes list
 [Int] is a list of Ints
 [Char] is a String
 This is why you can’t mix types in lists
 (Int, Bool) is a tuple with and Int and a Bool
Type declarations
 Use :: to declare type
 Type declarations can be used to remove ambiguity
Prelude> 5 :: Float
5.0
Prelude> True :: Float
:17:1:
Couldn't match expected type `Float' with actual type `Bool'
In the expression: True :: Float
In an equation for `it': it = True :: Float
Also declare the types of variables
pi :: Double
pi = 3.1415
Function types
 Function types are determined by parameter types and return type
 Parameter and return types separated by > arrows
sumThree :: Int > Int > Int > Int
sumThree x y z = x + y + z
Let’s annotate some functions
factorial n = product [1..n]
factorial :: Int > Integer
firstLetter :: [Char] > Char
fibHelper (a, b) 0 = a
fibHelper (a, b) 1 = b
fibHelper (a, b) n = fibHelper (b, a + b) (n  1)
fibHelper :: (Integer, Integer) > Int > Integer
Type variables

What is the type of
head
?

head :: [Char] > Char

head :: [Int] > Int

head :: [Bool] > Bool
 We use a type variable for the type
 head :: [a] > a
 a represents any type
 Type variables are like generics in Java
What is the type of
zip
?
zip :: [a] > [b] > [(a, b)]
Type classes
How about this function that tests equality and returns 1 or 0
foo :: a > a > Int
foo x y = if x == y then 1 else 0
Why won’t this compile?
 What if we can’t check the equality of values of type a?
 We need to impose a constraint on the type variable a
 We use type classes for this
Type classes
 Types belong to type classes
 Similar to interfaces in Java
 Below we enforce type variable a is of typeclass Eq
foo :: (Eq a) => a > a > Int
foo x y = if x == y then 1 else 0
 Types of class Ord have comparison operators defined

show :: (Show a) => a > String
is defined on types with class
Show
 Int, Integer, Float, Double are Nums
 Int, Integer are Integrals
 Float, Double are Fractionals
Partial Function Application
Lambdas
 Haskell has nice syntax for anonymous functions
addThree x = x + 3
addThree = (\x > x + 3)
Currying
 In lambda calculus, functions take one parameter
 How do you create a multivariable function?
 Currying!
Currying
 Currying is a way to convert a function with n parameters into a function returning a function with n  1 parameters
Here is an example without currying
sumThree x y z = x + y + z
Here is the curried form
sumThree = (\x > (\y > (\z > x + y + z))
Currying meets typing
What is the type of the uncurried form?
sumThree :: (Num a) => a > a > a > a
sumThree x y z = x + y + z
What is the type of the curried form?
sumThree :: (Num a) => a > (a > (a > a))
sumThree = (\x > (\y > (\z > x + y + z))
What if I told you > was right associative?
That would mean
sumThree :: (Num a) => a > (a > (a > a))
is equivalent to
sumThree :: (Num a) => a > a > a > a
Mind Blowing Slide No. 1
 All functions in Haskell take one parameter and are curried
 Haskell syntax makes it easy to forget this sometimes
 What does this mean?
ghci> let sumThree x y z = x + y + z
ghci> ((sumThree 1) 2) 3
6
Partial function application

If a function is called with fewer parameters than it takes, it is
partially applied
 You get back a new function that takes the remaining parameters
 This is super useful
Partial application example
Let’s write a function that returns a number if it is positive or 0 if it’s negative
makeNatural = (Num a) => a > a
makeNatural x = max 0 x
Partial application example
How about?
makeNatural = (Num a) => a > a
makeNatural = max 0
You can even partially apply infix functions
addThree = (Num a) => a > a
addThree = (+3)
Function composition
 . operator composes functions

(f . g) x = f (g x)
ghci> map (negate . abs) [1, 2, 4, 5]
[1, 2, 4, 5]
Function application operator
 Usually function application is performed using spaces
 $ is a lower precedence operator
ghci> map (2*) (filter (< 5) [1..])
[2, 4, 6, 8]
ghci> map (2*) filter (< 5) [1..]
 Crash!
ghci> map (2*) $ filter (< 5) [1..]
 Crash!
One more example
Let’s tighten up our
qsort
example
qsort [] = []
qsort (p:xs) = (qsort $ filter (<= p) xs) ++ [p] ++ (qsort $ filter (> p) xs)