Post on 05-Jan-2016
CS5205 Haskell 1
CS5205: Foundations in Programming Languages
FP with Haskell
A pure lazy functional language that embodies many innovative ideas in language design.
CS5205 Haskell 2
Haskell 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 3
Functions Functions
• Function is a black box that converts input to output. A basis of software component.
function
…. inputs
…. output
pure
function
…. inputs
…. output
impure
globalvars
CS5205 Haskell 4
Example of FunctionsExample 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 5
Expression-OrientedExpression-Oriented
• Instead of command/statement : if e1 then stmt1 else stmt2
• Instead of imperative commands/statements, the focus is on expression.
• We use conditional expressions :if e1 then e2 else e3
CS5205 Haskell 6
Expression-OrientedExpression-Oriented
• An example function:
fact :: Integer -> Integerfact n = if n=0 then 1
else n * fact (n-1)
• Can use pattern-matching instead of conditional
fact 0 = 1 fact n = n * fact (n-1)
fact n = case n of 0 -> 1 a -> a * fact (a-1)
• Alternatively:
CS5205 Haskell 7
Conditional Conditional Case Construct Case Construct
• Can be translated tocase e1 of True -> e2 False -> e3
• Conditional;if e1 then e2 else e3
length xs = case xs of [] -> 0;
y:ys -> 1+(length ys)
• Case also works over data structures (without any extra primitives)
Locally bound variables
CS5205 Haskell 8
Lexical Scoping Lexical Scoping
let y = a+bf x = (x+y)/y
in f c + f d
• Local variables can be created by let construct to give nested scope for the name space. Example:
• 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 9
Layout Rule Layout Rule
is being parsed as:
• Haskell uses two dimensional syntax that relies on declarations being “lined-up columnwise”
• 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.
let y = a+bf x = (x+y)/y
in f c + f d
let { y = a+b; f x = (x+y)/y }
in f c + f d
CS5205 Haskell 10
Expression EvaluationExpression Evaluation
• Expression can be computed (or evaluated) so that it is reduced to a value. This can be represented 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
e * v
• We can abbreviate above as:
CS5205 Haskell 11
Values and TypesValues 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 :: Integer'a' :: Char[1,2,3] :: [Integer]('b', 4) :: (Char, Integer)“cs5” :: String (same as [Char])
CS5205 Haskell 12
Built-In TypesBuilt-In Types
data Char = ‘a’ | ‘b’ | …data Int = -65532 | … | -1 | 0 | 1 | …. | 65532 data Integer = … | -2 | -1 | 0 | 1 | 2 | …
• They are not special:
• 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] = [] | a : [a]
[1,2,3] is short hand for 1 : (2 : (3 : []))
CS5205 Haskell 13
User-Defined Algebraic TypesUser-Defined Algebraic Types
data Bool = False | Truedata Color = Red | Green | Blue | Violet
• Can describe enumerations:
• Pt is a data constructor with type a -> a -> Point a
Pt 2.0 3.1 :: Point FloatPt ‘a’ ‘b’ :: Point CharPt True False :: Point Bool
• Can also describe a tuple
data Pair = P2 Integer Integerdata Point a = Pt a a
type variable
CS5205 Haskell 14
Recursive TypesRecursive Types
data Tree a = Leaf a | Branch (Tree a) (Tree a)
• Some types may be recursive:
• Two data constructors:
Leaf :: a -> Tree aBranch :: 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 15
Polymorphic TypesPolymorphic 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] -> Integerlength [] = 0length (x:xs) = 1 + length xs
CS5205 Haskell 16
Polymorphic TypesPolymorphic Types
length [1,2,3] ) 2length [‘a’, ’b’, ‘c’] ) 3length [[1],[],[3]] ) 3
• This polymorphic function can be used on list of any type..
• More examples :
head :: [a] -> ahead (x:xs) = x
tail :: [a] -> [a]tail (x:xs) = xs
• Note that head/tail are partial functions, while length is a total function?
CS5205 Haskell 17
Principal TypesPrincipal Types
• 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.
[Char] <: 8 a. [a] <: 8 a. a
• Some types are more general than others:
CS5205 Haskell 18
Type SynonymsType Synonyms
type String = [Char]type Person = (Name, Address)type Name = Stringdata Address = None | Addr String
• It is possible to provide new names for commonly used types
• 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 19
Type Classes and OverloadingType 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 20
Equality ClassEquality 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 -> Boolx /= y = not (x==y)
• Then: (==) :: Eq a => a -> a -> Bool
default definition
CS5205 Haskell 21
Members of Eq Type ClassMembers of Eq Type Class
• The class is open and can be extended, as follows:
instance Eq Integer wherex == y = x ‘integerEq’ y
• Recursive type can also be handled but elements may need to be given type qualifiers.
instance (Eq a) => Eq (Tree a) whereLeaf a == Leaf b = a==b(Branch l1 r1) == (Branch l2 r2)
= (l1==l2) && (r1==r2)_ == _ = False
instance Eq Float wherex == y = x ‘FloatEq’ y
CS5205 Haskell 22
More Members of Eq Type ClassMore Members of Eq Type Class
• Similarly, we may use structural equality for List:
• One use of Eq class is:
instance (Eq a) => Eq ([a]) where[] == [] = True(x:xs) == (y:ys) = (x==y) && (xs==ys)_ == _ = False
• Exercise : define Set as an instance of the Eq class.
elem :: (Eq a) => a -> [a] -> Boolx ‘elem’ [] = Falsex ‘elem’ (y:ys) = (x==y) || (x ‘elem’ ys)
CS5205 Haskell 23
Numeric ClassNumeric 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 Num Int where …instance Num Integer where …instance Num Float where …instance Num Double where …
CS5205 Haskell 24
Functions and its TypeFunctions 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 :: Num a => a -> a(\x -> x+1) :: Num a => a -> a
• Types can be user-supplied or inferred.
CS5205 Haskell 25
Functions and its TypeFunctions and its Type
• Some examples
(\x -> x+1) 3.2
• User can restrict the type, e.g.
inc :: Int -> Int
(\x -> x+1) 3
• In that case, some examples may be wrongly typed.
inc 3.2
inc 3
CS5205 Haskell 26
Function AbstractionFunction Abstraction
• Function abstraction is the ability to convert any expression into a function that is evaluated at a later time.
<Expr>
Normal Execution
time
p = \ () -> Expr
p ()
Delayed Execution
time
CS5205 Haskell 27
Higher-Order FunctionsHigher-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 28
FunctionsFunctions
• The first version allows a function to be returned as result after applying a single argument.
add2 :: (Integer,Integer) -> Integeradd2(x,y) = x+y
• Functions can be written in two main ways:
add :: Integer -> Integer -> Integeradd x y = x+y
inc :: Integer -> Integerinc = add 1
• The second version needs all arguments. Same effect requires a lambda abstraction:
inc = \ x -> add2(x,1)
CS5205 Haskell 29
FunctionsFunctions
• Functions can also be passed as parameters. Example:
map :: (a->b) -> [a] -> [b]map f [] = []map f (x:xs) = (f x) : (map f xs)
• Alternative ways of defining functions:
add = \ x -> \ y -> x+yadd = \ x y -> x+y
• Such higher-order function aids code reuse.
map (add 1) [1, 2, 3] ) [2, 3, 4]map add [1, 2, 3] ) [add 1, add 2, add 3]
CS5205 Haskell 30
GenericityGenericity• 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 31
Polymorphic, Higher-Order TypesPolymorphic, Higher-Order Types
sumList :: [Int] -> Int
sumList :: Num a => [a] -> a
foldr :: (a -> b -> b) -> b -> [a] -> b
CS5205 Haskell 32
Instantiating Generic FunctionsInstantiating Generic Functions
sumL2 :: Num a => [a] -> asumL2 ls = foldr (+) 0 ls
sumL2 [1, 2, 3] )
sumL2 [1.1, 3, 2.3] )
CS5205 Haskell 33
Instantiating Generic FunctionsInstantiating Generic Functions
prodL :: Num a => [a] -> aprodL ls = foldr (*) 1 ls
prodL [1, 2, 5] )
prodL [1.1, 3, 2.3] )
CS5205 Haskell 34
Instantiating Generic FunctionsInstantiating Generic Functions
map :: (a -> b) -> [a] -> [b]map f [] = []map f (x:xs) = (f x) : (map f xs)
map f xs = foldr … … … xs
• Can you express map in terms of foldr?
CS5205 Haskell 35
Instantiating Generic FunctionsInstantiating Generic Functions
filter :: (a -> Bool) -> [a] -> [a]filter f [] = []filter f (x:xs) =
if (f x) then x : (filter f xs)else x : filter f xs
• Filtering a list of elements with a predicate.
filter f xs = foldr … … … xs
• Can we express filter in terms of foldr?
CS5205 Haskell 36
Pipe/ComposePipe/Compose
compose :: (b -> c) -> (a -> b)-> a -> c
compose f g = \ x -> f (g x)g | f = compose f g
cmd1 | cmd2
• Similar to Unix pipe command:
CS5205 Haskell 37
Iterator Construct Iterator Construct
for :: Int -> Int -> (Int -> a -> a) -> a -> a
for i j f a = if i>j then aelse f (i+1) j (f i a)
for :: Num b, Ord b => b -> b ->(b -> a -> a) -> a -> a
• In Haskell, type class help give a more generic type:
CS5205 Haskell 38
Right Folding 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 39
Left Folding – Tail Recursion 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
• What is the type of foldl?
• Can we compute factorial using it?
based on accumulation
CS5205 Haskell 40
Left Folding 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 41
Instance of Left FoldingInstance 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 42
Infix OperatorInfix Operator
• Another example is function composition.
• Infix operators are distinguished entirely by symbols:
(++) :: [a]-> [a] -> [a][] ++ ys = ys(x:xs) ++ ys = x : (xs ++ ys)
• Infix operator can be coerced to prefix by bracketing, e.g. map (+) [1,2,3]
(.) :: (b->c) -> (a->b) -> (a->c)f . g = \ x -> f (g x)
• Alphanumeric named function can be made infix too, e.g. a ‘add’ b x ‘elem’ xs
CS5205 Haskell 43
SectionsSections
• Other examples:.
• Infix operators can also be partially applied:
(x+) ´ \y -> x+y(+y) ´ \x -> x+y(+) ´ \x y -> x+y
• These are syntactic sugar for programming conveniences.
inc = (+ 1)add = (+)