CS5205: Foundations in
Programming Languages
FP with Haskell
A pure lazy functional language that
embodies many innovative ideas
in language design.
CS5205
Haskell
1
Haskell
• Advanced programming language – reusable,
abstract, efficient, feature-rich.
• Functions and Expressions
• Values, Types and Lazy evaluation
• Products, Records and Algebraic Types
• Polymorphic Types & Type Classes
• Higher-Order Functions
• Infix operator and sections.
Reference --- A Gentle Introduction to Haskell 98
http://www.haskell.org/tutorial
CS5205
Haskell
2
Functions
• Function is a black box that converts input to
output. A basis of software component.
….
….
inputs
function
….
global
vars
function
….
output
output
impure
pure
CS5205
inputs
Haskell
3
Example of Functions
• Double a given input.
square :: Int -> Int
square x = x*x
• Conversion from fahrenheit to celcius
fahr_to_celcius :: Float -> Float
fahr_to_celcius temp = (temp – 32)/1.8
• A function with multiple results - quotient & remainder
divide ::
Int -> Int -> (Int,Int)
divide x y = (div x y, mod x y)
CS5205
Haskell
4
Expression-Oriented
• Instead of imperative commands/statements, the focus is
on expression.
• Instead of command/statement :
if e1 then stmt1 else stmt2
• We use conditional expressions :
if e1 then e2 else e3
CS5205
Haskell
5
Expression-Oriented
• An example function:
fact
fact n
:: Integer -> Integer
= if n=0 then 1
else n * fact (n-1)
• Can use pattern-matching instead of conditional
fact 0
fact n
= 1
= n * fact (n-1)
• Alternatively:
fact n
CS5205
= case n of
0 -> 1
a -> a * fact (a-1)
Haskell
6
Conditional Case Construct
• Conditional;
if e1 then e2 else e3
• Can be translated to
case e1 of
True -> e2
False -> e3
• Case also works over data structures (without any extra
primitives)
length xs = case xs of
[] -> 0;
y:ys -> 1+(length ys)
Locally bound variables
CS5205
Haskell
7
Lexical Scoping
• Local variables can be created by let construct to give
nested scope for the name space. Example:
let y
= a+b
f x = (x+y)/y
in f c + f d
• For scope bindings over guarded expressions, we
require a where construct instead:
f x y
| x>z = …
| y==z = …
| y<z = ….
where z=x*x
CS5205
Haskell
8
Layout Rule
• Haskell uses two dimensional syntax that relies on
declarations being “lined-up columnwise”
let y
= a+b
f x = (x+y)/y
in f c + f d
is being parsed as:
let
{ y
= a+b
; f x = (x+y)/y }
in f c + f d
• Rule : Next character after keywords where/let/of/do
determines the starting columns for declarations.
Starting after this point continues a declaration, while
starting before this point terminates a declaration.
CS5205
Haskell
9
Expression Evaluation
• Expression can be computed (or evaluated) so that it is
reduced to a value. This can be represented as:
e
..
v
• We can abbreviate above as:
e
*
v
• A concrete example of this is:
inc (inc 3) inc (4) 5
• Type preservation theorem says that:
if e :: t Æ e v , it follows that v :: t
CS5205
Haskell
10
Values and Types
• As a purely functional language, all computations are
done via evaluating expressions (syntactic sugar) to
yield values (normal forms as answers).
• Each expression has a type which denotes the set of
possible outcomes.
• v :: t can be read as value v has type t.
• Examples of typings, associating a value with its
corresponding type are:
5
'a'
[1,2,3]
('b', 4)
“cs5”
CS5205
::
::
::
::
::
Integer
Char
[Integer]
(Char, Integer)
String (same as [Char])
Haskell
11
Built-In Types
• They are not special:
data Char
data Int
data Integer
= ‘a’ | ‘b’ | …
= -65532 | … | -1 | 0 | 1 | …. | 65532
= … | -2 | -1 | 0 | 1 | 2 | …
• Tuples are also built-in.
data (a,b)
= M2(a,b)
data (a,b,c)
= M3(a,b,c)
data (a,b.c.d) = M4(a,b,c,d)
• List type uses an infix operator:
data [a]
[1,2,3]
CS5205
= []
is short hand for
Haskell
|
a : [a]
1 : (2 : (3 : []))
12
User-Defined Algebraic Types
• Can describe enumerations:
data Bool
data Color
= False | True
= Red | Green | Blue | Violet
• Can also describe a tuple
data Pair
= P2 Integer Integer
data Point a = Pt a a
type variable
• Pt is a data constructor with type a -> a -> Point a
Pt 2.0 3.1
Pt ‘a’ ‘b’
Pt True False
CS5205
:: Point Float
:: Point Char
:: Point Bool
Haskell
13
Recursive Types
• Some types may be recursive:
data Tree a = Leaf a | Branch (Tree a) (Tree a)
• Two data constructors:
Leaf
:: a -> Tree a
Branch :: Tree a -> Tree a -> Tree a
• An example function over recursive types:
fringe :: Tree a -> [a]
fringe (Leaf x)
= [x]
fringe (Branch left right) = (fringe left) ++
(fringe right)
CS5205
Haskell
14
Polymorphic Types
• Support types that are universally quantified in some
way over all types.
• 8 c. [c] denotes a family of types, for every type c, the type
of lists of c.
• Covers [Integer],
[Char], [Integer->Integer],
etc.
• Polymorphism help support reusable code, e.g
length
:: 8 a. [a] -> Integer
length []
= 0
length (x:xs) = 1 + length xs
CS5205
Haskell
15
Polymorphic Types
• This polymorphic function can be used on list of any type..
length [1,2,3]
length [‘a’, ’b’, ‘c’]
length [[1],[],[3]]
)
)
)
2
3
3
• More examples :
head
head (x:xs)
:: [a] -> a
= x
tail
tail (x:xs)
:: [a] -> [a]
= xs
• Note that head/tail are partial functions, while length is
a total function?
CS5205
Haskell
16
Principal Types
• Some types are more general than others:
[Char]
<:
8 a. [a]
<:
8 a. a
• An expression’s principal type is the least general type
that contains all instances of the expression.
• For example, the principal type of head function is
[a]->a, while [b] -> a, b -> a, a are correct but
too general but [Integer] -> Integer is too
specific.
• Principal type can help supports software reusability
with accurate type information.
CS5205
Haskell
17
Type Synonyms
• It is possible to provide new names for commonly used
types
type
type
type
data
String
Person
Name
Address
=
=
=
=
[Char]
(Name, Address)
String
None | Addr String
• Type synonyms do not define new types, but simply
give new names for existing types.
type AssocList a b = [(a,b)]
• Their use can improve code readability.
CS5205
Haskell
18
Type Classes and Overloading
• Parametric polymorphism works for all types. However,
ad-hoc polymorphism works for a class of types and can
systematically support overloading.
• For example, what is the type for (+) operator?
(+) :: a -> a -> a
(+) :: Int -> Int -> Int
(+) :: Float -> Float -> Float
• What about methods built from (+)?
double x = x+x
• Better solution is to use a type class for numerics!
(+) :: Num a => a -> a -> a
double :: Num a => a -> a
CS5205
Haskell
19
Equality Class
• Similar issue with equality. Though it looks like:
(==) :: a -> a -> Bool
• Equality can be tested for data structures but not
functions!
• Solution is to define a type class that supports the
equality method, as follows:
class Eq a where
(==),(/=) :: a -> a -> Bool
x /= y
= not (x==y)
default definition
• Then:
CS5205
(==) :: Eq a => a -> a -> Bool
Haskell
20
Members of Eq Type Class
• The class is open and can be extended, as follows:
instance Eq Integer where
x == y
= x ‘integerEq’ y
instance Eq Float where
x == y
= x ‘FloatEq’ y
• Recursive type can also be handled but elements may
need to be given type qualifiers.
instance (Eq a) => Eq (Tree a) where
Leaf a == Leaf b = a==b
(Branch l1 r1) == (Branch l2 r2)
= (l1==l2) && (r1==r2)
_ == _
= False
CS5205
Haskell
21
More Members of Eq Type Class
• Similarly, we may use structural equality for List:
instance (Eq a) => Eq
[] == []
(x:xs) == (y:ys)
_ == _
([a]) where
= True
= (x==y) && (xs==ys)
= False
• One use of Eq class is:
elem :: (Eq a) => a -> [a] -> Bool
x ‘elem’ []
= False
x ‘elem’ (y:ys)
= (x==y) || (x ‘elem’ ys)
• Exercise : define Set as an instance of the Eq class.
CS5205
Haskell
22
Numeric Class
• There is a hierarchy of numeric classes. Most basic is:
class Num a where
(+),(-),(*) :: a -> a -> a
negate,abs,signum :: a -> a
fromInteger :: Integer -> a
x – y
= x + (negate y)
negate x = 0 – x
instance
…
instance
…
instance
…
instance
…
CS5205
Num Int where
Num Integer where
Num Float where
Num Double where
Haskell
23
Functions and its Type
• Method to increment its input
inc x
=
x+1
• Or through lambda expression (anonymous functions)
(\ x -> x+1)
• They can also be given suitable function typing:
inc
(\x -> x+1)
:: Num a => a -> a
:: Num a => a -> a
• Types can be user-supplied or inferred.
CS5205
Haskell
24
Functions and its Type
• Some examples
(\x -> x+1) 3.2
(\x -> x+1) 3
• User can restrict the type, e.g.
inc
:: Int -> Int
• In that case, some examples may be wrongly typed.
inc 3.2
inc 3
CS5205
Haskell
25
Function Abstraction
• Function abstraction is the ability to convert any
expression into a function that is evaluated at a later
time.
<Expr>
p = \ () -> Expr
time
p ()
time
Normal Execution
CS5205
Delayed Execution
Haskell
26
Higher-Order Functions
• Higher-order programming treats functions as first-class,
allowing them to be passed as parameters, returned as
results or stored into data structures.
• This concept supports generic coding, and allows
programming to be carried out at a more abstract level.
• Genericity can be applied to a function by letting
specific operation/value in the function body to become
parameters.
CS5205
Haskell
27
Functions
• Functions can be written in two main ways:
add
add x y
:: Integer -> Integer -> Integer
= x+y
add2
add2(x,y)
:: (Integer,Integer) -> Integer
= x+y
• The first version allows a function to be returned as
result after applying a single argument.
inc
inc
:: Integer -> Integer
= add 1
• The second version needs all arguments. Same effect
requires a lambda abstraction:
inc
CS5205
= \ x -> add2(x,1)
Haskell
28
Functions
• Functions can also be passed as parameters. Example:
map
:: (a->b) -> [a] -> [b]
map f []
= []
map f (x:xs) = (f x) : (map f xs)
• Such higher-order function aids code reuse.
map (add 1) [1, 2, 3]
map add [1, 2, 3]
) [2, 3, 4]
) [add 1, add 2, add 3]
• Alternative ways of defining functions:
add
add
CS5205
= \ x -> \ y -> x+y
= \ x y -> x+y
Haskell
29
Genericity
• Replace specific entities (0 and +) by parameters.
sumList ls =
case ls of
[]
-> 0
x:xs -> x+(sumList xs)
foldr f u ls =
case ls of
[]
-> u
x:xs -> f x (foldr f u xs)
CS5205
Haskell
30
Polymorphic, Higher-Order Types
sumList :: [Int] -> Int
sumList :: Num a => [a] -> a
foldr :: (a -> b -> b) -> b
-> [a] -> b
CS5205
Haskell
31
Instantiating Generic Functions
sumL2 :: Num a => [a] -> a
sumL2 ls = foldr (+) 0 ls
sumL2 [1, 2, 3]
)
sumL2 [1.1, 3, 2.3]
)
CS5205
Haskell
32
Instantiating Generic Functions
prodL :: Num a => [a] -> a
prodL ls = foldr (*) 1 ls
prodL [1, 2, 5]
)
prodL [1.1, 3, 2.3]
)
CS5205
Haskell
33
Instantiating Generic Functions
• Can you express map in terms of foldr?
map :: (a -> b) -> [a] -> [b]
map f []
= []
map f (x:xs) = (f x) : (map f xs)
map f xs
CS5205
= foldr … … … xs
Haskell
34
Instantiating Generic Functions
• Filtering a list of elements with a predicate.
filter :: (a -> Bool) -> [a] -> [a]
filter f []
= []
filter f (x:xs) =
if (f x) then x : (filter f xs)
else x : filter f xs
• Can we express filter in terms of foldr?
filter f xs
CS5205
= foldr … … … xs
Haskell
35
Pipe/Compose
compose :: (b -> c) -> (a -> b)
-> a -> c
compose f g
= \ x -> f (g x)
g | f
= compose f g
• Similar to Unix pipe command:
cmd1
CS5205
|
cmd2
Haskell
36
Iterator Construct
for :: Int -> Int -> (Int -> a -> a)
-> a -> a
for i j f a
=
if i>j then a
else f (i+1) j (f i a)
• In Haskell, type class help give a more generic type:
for :: Num b, Ord b => b -> b ->
(b -> a -> a) -> a -> a
CS5205
Haskell
37
Right Folding
foldr f u [x1,x2,..,xn]
f x1 (foldr f u [x2 ..xn])
f x1 (f x2 (fold f u [x3..xn]))
f x1 (f x2 (… (fold f u [xn]) …))
f x1 (f x2 (… (f xn u) …)))
associate to
right
CS5205
Haskell
38
Left Folding – Tail Recursion
• Accumulate result in a parameter:
foldl f u ls =
case ls of
[]
-> u
x:xs -> foldl f (f u x) xs
based on accumulation
• What is the type of foldl?
• Can we compute factorial using it?
CS5205
Haskell
39
Left Folding
foldl f u [x1,x2,..,xn]
foldl f (f u x1) [x2 ..xn]
foldl f (f (f u x1) x2) [x3..xn]))
foldl f (f … (f (f u x1) x2)… xn) []
f (… (f (f u x1) x2) …) xn
left is here!
CS5205
Haskell
40
Instance of Left Folding
• Summing a list by accumulation.
sumT acc ls =
case ls of
[]
-> 0
x:xs -> sumT (x+acc) xs
sumList ls = sumT 0 ls
sumT acc ls = foldl (+) acc ls
CS5205
Haskell
41
Infix Operator
• Infix operators are distinguished entirely by symbols:
(++)
[] ++ ys
(x:xs) ++ ys
:: [a]-> [a] -> [a]
= ys
= x : (xs ++ ys)
• Another example is function composition.
(.)
f . g
:: (b->c) -> (a->b) -> (a->c)
= \ x -> f (g x)
• Infix operator can be coerced to prefix by bracketing,
e.g. map (+) [1,2,3]
• Alphanumeric named function can be made infix too,
e.g. a ‘add’ b
x ‘elem’ xs
CS5205
Haskell
42
Sections
• Infix operators can also be partially applied:
(x+)
(+y)
(+)
´
´
´
\y -> x+y
\x -> x+y
\x y -> x+y
=
=
(+ 1)
(+)
• Other examples:.
inc
add
• These are syntactic sugar for programming
conveniences.
CS5205
Haskell
43
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )