an introduction toan introduction to functional ...”ιαφάνειες/haskell...haskell the most...
Post on 05-Apr-2021
17 Views
Preview:
TRANSCRIPT
An introduction toAn introduction toAn introduction to An introduction to functional programmingfunctional programmingfunctional programming functional programming using Haskellusing Haskellgg
Anders Mølleramoeller@cs au dkamoeller@cs.au.dk
HaskellHaskellHaskellHaskell
The most popular purely functional, lazy programming p p p y , y p g glanguage
“Functional programming language”:Functional programming language : – a program is a collection of mathematical functions
“Purely functional”: – all variables refer to immutable, persistent values– that is, new values can be created, but existing
ones cannot be modified!
“Lazy”:– expressions are evaluated “by need”
22
e p ess o s a e e a ua ed by eed
Example: QuickSort in JavaExample: QuickSort in JavaExample: QuickSort in JavaExample: QuickSort in Java
void qsort(int[] a, int lo, int hi) { q , ,if (lo < hi) { int l = lo; int h = hi; int p a[lo];int p = a[lo]; do {
while (l < h && a[l] <= p) l = l+1; while (h > l && a[h] >= p) h = h-1; pif (l < h) { int t = a[l]; a[l] = a[h]; a[h] t;
Mini-exercise:a[h] = t;
} } while (l < h); int t = a[h];
Sort the list a[h] = a[lo]; a[lo] = t; qsort(a, lo, h-1); qsort(a h+1 hi);
[4,8,1,7]
using QuickSort
33
qsort(a, h+1, hi); }
}
g Q
Example: QuickSort in HaskellExample: QuickSort in HaskellExample: QuickSort in HaskellExample: QuickSort in Haskell
t [] []qsort [] = []
qsort (x:xs) =
qsort lt ++ [x] ++ qsort greqqsort lt ++ [x] ++ qsort greq
where lt = [y | y <- xs, y < x]
greq = [y | y <- xs, y >= x]
The program is the specification!
g
List operations:[] the empty list[] the empty listx:xs adds an element x to the head of a list xsxs ++ ys concatenates two lists xs and ys
44
xs ++ ys concatenates two lists xs and ys[x,y,z] abbreviation of x:(y:(z:[]))
OverviewOverviewOverviewOverview
Definitions functions expressions and valuesDefinitions, functions, expressions, and valuesStrong typing
Recursive data structuresRecursive data structuresHigher-order functions
Programming styles, performanceReasoning about program behaviorReasoning about program behavior
55
Definitions, functions, expressions, Definitions, functions, expressions, d ld land valuesand values
len [] = 0len [] = 0
len (x:xs) = len xs + 1
numbers = [7,9,13]
n = len numbers
Function application can be written without parenthesesparentheses
Functions are reminiscent of methods in Java butFunctions are reminiscent of methods in Java, but …
66
Evaluation through pattern matchingEvaluation through pattern matchingd i i id i i iand expression rewritingand expression rewriting
len [] = 0len [] = 0
len (x:xs) = len xs + 1
numbers = [7,9,13]
n = len numbers
n ⇒ len numbers ⇒ len [7,9,13] ⇒len 7:[9 13] ⇒ len [9 13] + 1 ⇒len 7:[9,13] ⇒ len [9,13] + 1 ⇒len 9:[13] + 1 ⇒ len [13] + 1 + 1 ⇒len 13:[] + 1 + 1 ⇒ len [] + 1 + 1 + 1 ⇒0 + 1 + 1 + 1 ⇒ 1 + 1 + 1 ⇒ 2 + 1 ⇒ 30 + 1 + 1 + 1 ⇒ 1 + 1 + 1 ⇒ 2 + 1 ⇒ 3
Actual evaluation may proceed in a different order,
77
but the resulting value is the same
letlet expressionsexpressions
len [] = 0
letlet expressionsexpressions
len [] = 0
len (x:xs) = len xs + 1
numbers = [7,9,13]
n = len numbers
numbers = [7,9,13]
n = let len [] = 0
len (x:xs) len xs + 1len (x:xs) = len xs + 1
in len numbers
88
wherewhere clausesclauses
len [] = 0
wherewhere clausesclauses
len [] = 0
len (x:xs) = len xs + 1
numbers = [7,9,13]
n = len numbers
numbers = [7,9,13]
n = let len [] = 0
len (x:xs) len xs + 1len (x:xs) = len xs + 1
in len numbers
numbers = [7,9,13][ , , ]
n = len numbers
where len [] = 0
99
len (x:xs) = len xs + 1
casecase expressionsexpressions
len [] = 0
casecase expressionsexpressions
len [] = 0
len (x:xs) = len xs + 1
numbers = [7,9,13]
n = len numbers
numbers = [7,9,13]
n = let len [] = 0
len (x:xs) len xs + 1len ys = case ys oflen (x:xs) = len xs + 1
in len numbers numbers = [7,9,13]
len ys = case ys of
[] -> 0
x:xs -> len xs + 1
n = len numbers
where len [] = 0
l ( ) l 1
numbers = [7,9,13]
1010
len (x:xs) = len xs + 1 n = len numbers
Wildcard patternWildcard pattern
len [] = 0
Wildcard patternWildcard pattern
len [] = 0
len (x:xs) = len xs + 1
numbers = [7,9,13]
n = len numbers len (x:xs) = len xs + 1
numbers = [7,9,13]
n = let len [] = 0
len (x:xs) len xs + 1len ys = case ys of
len __ = 0
numbers [7 9 13]len (x:xs) = len xs + 1
in len numbers numbers = [7,9,13]
len ys = case ys of
[] -> 0
x:xs -> len xs + 1
numbers = [7,9,13]
n = len numbers
n = len numbers
where len [] = 0
l ( ) l 1
numbers = [7,9,13]
1111
len (x:xs) = len xs + 1 n = len numbers
Pattern matching, ifPattern matching, if--thenthen--else, and guardselse, and guardsPattern matching, ifPattern matching, if thenthen else, and guardselse, and guards
Multiple function definitions with the sameMultiple function definitions with the same function namecase expressionscase expressionsif-then-else expressions:
case e ofif e1 then e2 else e3case e1 ofTrue -> e2False -> e3
≈
Guards:
i | 0 1
False > e3
sign x | x > 0 = 1| x == 0 = 0| x < 0 = -1
1212
| x < 0 = 1
Iteration and recursionIteration and recursionIteration and recursionIteration and recursion
We don’t need loops when we have recursionWe don t need loops when we have recursionDivide and conquer!
len [] = 0
len (x:xs) = len xs + 1
qsort [] = []qsort [] []
qsort (x:xs) =
qsort lt ++ [x] ++ qsort greq
where lt = [y | y <- xs, y < x]
greq = [y | y <- xs, y >= x]
1313
Layout of Haskell programsLayout of Haskell programsLayout of Haskell programsLayout of Haskell programs
numbers = [7 9 13]numbers = [7,9,13]
n = let len [] = 0
len (x:xs) = len xs + 1
in len numbers
÷÷numbers = [7,9,13]
n = let len [] = 0
len (x:xs) len xs + 1 ÷÷len (x:xs) = len xs + 1
in len numbers
numbers = [7,9,13]
n = let {len [] = 0; len (x:xs) = len xs + 1}
1414
in len numbers
CommentsCommentsCommentsComments
---- computes the length of a list
len [] = 0
len (x:xs) = len xs + 1
{{-
numbers = [7,9,13]
n = len numbers
-}
1515
Quiz!Quiz!Quiz!Quiz!
Write a function rev that reverses a given listWrite a function rev that reverses a given list
for example,rev [7 9 13] ⇒ [13 9 7]
for example,rev [7 9 13] ⇒ [13 9 7]rev [7,9,13] ⇒ [13,9,7]
(d ’ b f f )
rev [7,9,13] ⇒ [13,9,7]
(d ’ b f f )(don’t worry about performance for now...)(don’t worry about performance for now...)
len [] = 0
Hint: recall the definition of len:
1616
len (x:xs) = len xs + 1
OverviewOverviewOverviewOverview
Definitions functions expressions and valuesDefinitions, functions, expressions, and valuesStrong typing
Recursive data structuresRecursive data structures Higher-order functions
Programming styles, performanceReasoning about program behaviorReasoning about program behavior
1717
Strong typingStrong typingStrong typingStrong typing
len :: [Integer] -> Integerlen :: [Integer] > Integer
len [] = 0
len (x:xs) = len xs + 1
numbers :: [Integer]
b [7 9 13]numbers = [7,9,13]
n :: Integern :: Integer
n = len numbers
Every expression has a typeThe Haskell static type checker makes sure you are
t i i l d b1818
not mixing apples and bananas
TypesTypesTypesTypes
i l h bInteger, String, Float, Char, ... – base types[X] – a list of X valuesX -> Y – a function from X values to Y values(X,Y,Z) – a tuple of an X value, a Y value,
d land a Z value ...
pair_sum :: (Integer,Integer) -> Integer
pair_sum (a,b) = a + b
x :: (Integer,(String,Integer),Char)
” ” 42
1919
x = (7,(”Foo”,42),’a’)
Type errors at compileType errors at compile--timetimeType errors at compileType errors at compile timetime
qsort [] = []qsort [] = []
qsort (x:xs) =
qsort lt + [x] + qsort greq
where lt = [y | y <- xs, y < x]
greq = [y | y <- xs, y >= x]
Can you spot the error?
The Hugs tool: ERROR: ”example.hs”:42 – Cannot infer instanceERROR: ”example.hs”:42 – Cannot infer instance
The error is found but the quality of type error
*** Instance : Num [a]*** Expression : qsort*** Instance : Num [a]*** Expression : qsort
2020
The error is found, but the quality of type error messages is not always great...
Type inferenceType inferenceType inferenceType inference
A type annotation is a contract between the authorA type annotation is a contract between the author and the user of a function definitionIn Haskell, writing type annotations is optionalIn Haskell, writing type annotations is optional– use them to express the intended meaning
of your functions– omit them if the meaning is “obvious”
(Compare this with Java!)
When omitted, Haskell finds the type for you!i f t th b t ibl t !...in fact, the best possible type!
(also called, the principal type)
2121More about type inference later...
OverviewOverviewOverviewOverview
Definitions functions expressions and valuesDefinitions, functions, expressions, and valuesStrong typing
Recursive data structuresRecursive data structuresHigher-order functions
Programming styles, performanceReasoning about program behaviorReasoning about program behavior
2222
Type definitionsType definitionsType definitionsType definitions
data Color = Red | Green | Blue
f Red = 1
f Green = 2
f ldata Shape Rectangle Float Floatf Blue = 3data Shape = Rectangle Float Float
| Circle Float
area (Rectangle x y) = x * y
area (Circle r) = pi * r * r
Red, Green, Blue, Rectangle, and Circlell d t t
2323
are called constructors
Constructors vs. pattern matchingConstructors vs. pattern matchingConstructors vs. pattern matchingConstructors vs. pattern matching
Constructors are special functions thatConstructors are special functions that construct values
lexample:Rectangle 3.0 4.0constructs a Shape valueconstructs a Shape value
Pattern matching can be used to “destruct” valuesPattern matching can be used to destruct values
example:getX (Rectangle x y) xgetX (Rectangle x y) = xdefines a function that can extract the x component of a Rectangle value
2424
Recursive data structuresRecursive data structuresRecursive data structuresRecursive data structures
Type definitions can be recursive!Type definitions can be recursive!
data Expr = Const Float
Mult
C t Add| Add Expr Expr
| Neg Expr
| Mult Expr Expr
Const
Const Const
Add
2.0
| Mult Expr Expr
eval (Const c) = c
3.0 4.0
eval (Const c) c
eval (Add e1 e2) = eval e1 + eval e2
eval (Neg e) = - eval e
eval (Mult (Const 2 0) (Add (Const 3 0) (Const 4 0)))
eval (Mult e1 e2) = eval e1 * eval e2
2525
eval (Mult (Const 2.0) (Add (Const 3.0) (Const 4.0))) ⇒ ... ⇒ 14.0
Type synonymsType synonymsType synonymsType synonyms
type String [Char]type String = [Char]
type Name = String
data OptionalAddress = None | Addr Stringp | g
type Person = (Name,OptionalAddress)
Type synonyms are just abbreviations...
2626
Naming requirementsNaming requirementsNaming requirementsNaming requirements
The naming style we have been using is mandatory:
– Type names and constructor names begin with an upper-case letter (e.g. Expr or Rectangle)
– Value names begin with a lower-case letter(e.g. qsort or x)( g q )
2727
Quiz!Quiz!Quiz!Quiz!
Given the type definitionGiven the type definition
data TreeNode = Leaf Integer
| Branch TreeNode TreeNode
data TreeNode = Leaf Integer
| Branch TreeNode TreeNode| Branch TreeNode TreeNode
write a function leafSum that computes
| Branch TreeNode TreeNode
write a function leafSum that computes pthe sum of the leaf values for a given TreeNode structure
pthe sum of the leaf values for a given TreeNode structureTreeNode structureTreeNode structure
2828
OverviewOverviewOverviewOverview
Definitions functions expressions and valuesDefinitions, functions, expressions, and valuesStrong typing
Recursive data structuresRecursive data structuresHigher-order functions
Programming styles, performanceReasoning about program behaviorReasoning about program behavior
2929
HigherHigher--order functionsorder functionsHigherHigher order functionsorder functions
Functions are first-class values! (unlike methods in Java )Functions are first class values! (unlike methods in Java...)
Functions can take functions as arguments and return functionsreturn functions
map f [] = []
f ( ) f fmap f (x:xs) = f x : map f xs
numbers = [7 9 13]numbers = [7,9,13]
inc x = x + 1
more_numbers = map inc numbers
Function application associates to the left:
3030
f x y ≈ (f x) y
CurryingCurryingCurryingCurrying
add A :: (Integer Integer) -> Integeradd_A :: (Integer,Integer) > Integer
add_A (x,y) = x + y
add B :: Integer -> Integer -> Integeradd_B :: Integer > Integer > Integer
add_B x y = x + y
inc = add B 1
add_A takes a pair of integers as argument and
inc = add_B 1
returns their sumadd_B takes one integer as argument and returns a f ti th t t k th i t t dfunction that takes another integer as argument and returns their sum
3131This trick is named after Haskell B. Curry (1900-1982)
Anonymous functionsAnonymous functionsAnonymous functionsAnonymous functions
A λ b t ti i f tiA λ-abstraction is an anonymous function
Traditional syntax: yλx.exp where x is a variable name and
exp is an expression that may use x(λ is like a quantifier)
Haskell syntax:Haskell syntax: \x -> exp
inc x = x + 1 inc = \x -> x + 1≈
3232
add x y = x + y add = \x -> \y -> x + y≈
Infix operatorsInfix operatorsInfix operatorsInfix operators
Infix operators (e g + or ++) are just binary functions!Infix operators (e.g. + or ++) are just binary functions!
x + y (+) x y≈
Binary functions can be written with an infix notationBinary functions can be written with an infix notation
add x y x `̀add`̀ y≈
Operator precedence and associativity can beOperator precedence and associativity can be specified with “fixity declarations”...
3333
Haskell standard preludeHaskell standard preludeHaskell standard preludeHaskell standard prelude
A library containing commonly used definitionsA library containing commonly used definitions
Examples: [] ++ ys = ys
(x:xs) ++ ys x : (xs ++ ys)(x:xs) ++ ys = x : (xs ++ ys)
True && x = x
False && _ = False
t St i [Ch ]type String = [Char]
data Bool = False | True
The core of Haskell is quite small
|
3434
Theoretically, everything can be reduced to the λ-calculus...
List comprehensionsList comprehensions
Lists are pervasive in Haskell
List comprehensionsList comprehensions
Lists are pervasive in Haskell...
lt = [y | y <- xs y < x]
means the same as
lt = [y | y < xs, y < x]
lt = concatMap f xs
where
f y | y < x = [y]
| otherwise = []
3535
(concatMap is defined in the standard prelude)
An operation on lists:An operation on lists: zipzipAn operation on lists: An operation on lists: zipzip
zip takes two lists as input (Curry style) and returnszip takes two lists as input (Curry style) and returns a list of pairs
Example:zip [1,2,3] ['a','b','c']p [ , , ] [ , , ]evaluates to[(1,'a'),(2,'b'),(3,'c')]
How is zip defined?
zip (x:xs) (y:ys) = (x,y) : zip xs ys
zip [] ys = []
3636
zip xs [] = []
Quiz!Quiz!Quiz!Quiz!
Explain why the following 3 definitions have theExplain why the following 3 definitions have thep y gsame meaning – and describe what they do:
p y gsame meaning – and describe what they do:
(f . g) x = f (g x)
( ) f f ( )
(f . g) x = f (g x)
( ) f f ( )(.) f g x = f (g x)
f . g = \x -> f (g x)
(.) f g x = f (g x)
f . g = \x -> f (g x)g \ (g )g \ (g )
3737
OverviewOverviewOverviewOverview
Definitions functions expressions and valuesDefinitions, functions, expressions, and valuesStrong typing
Recursive data structuresRecursive data structures Higher-order functions
Programming styles, performanceReasoning about program behaviorReasoning about program behavior
3838
Syntactic redundancySyntactic redundancySyntactic redundancySyntactic redundancy
Expression style Declaration stylevsExpression style
h f ti i d fi d
Declaration style
h f ti i d fi d
vs.
each function is defined as one expression
each function is defined as a series of equations
let where
λ arguments on left-hand-side of ‘=’
f ti l l tt t hicase
if
function-level pattern matching
guards
3939
if guards
A note on performanceA note on performanceA note on performanceA note on performance
Being in math world doesn’t mean that we canBeing in math world doesn t mean that we can ignore performance...Assume that we define reverse byAssume that we define reverse by
reverse [] = []
reverse (x:xs) = reverse xs ++ [x]
Recall that ++ is defined by
reverse (x:xs) = reverse xs ++ [x]
Recall that ++ is defined by
[] ++ ys = ys
(x:xs) ++ ys x : (xs ++ ys)
Computing reverse zs takes time O(n 2)
(x:xs) ++ ys = x : (xs ++ ys)
4040
Computing reverse zs takes time O(n 2)where n is the length of zs
A fasterA faster reversereverse using an accumulatorusing an accumulatorA faster A faster reversereverse using an accumulatorusing an accumulator
reverse zs = rev [] zs
where rev acc [] = acc
rev acc (x:xs) = rev (x:acc) xs
reverse [7,9,13] ⇒ rev [] [7,9,13] ⇒rev [7] [9,13] ⇒ rev [9,7] [13] ⇒rev [13 9 7] [] ⇒ [13 9 7]rev [13,9,7] [] ⇒ [13,9,7]
Computing reverse zs now takes time O(n )p g ( )where n is the length of zs
4141
Moral: you have to know how programs are evaluated
OverviewOverviewOverviewOverview
Definitions functions expressions and valuesDefinitions, functions, expressions, and valuesStrong typing
Recursive data structuresRecursive data structuresHigher-order functions
Programming styles, performanceReasoning about program behaviorReasoning about program behavior
4242
Referential transparencyReferential transparencyReferential transparencyReferential transparency
Purely functional means that evaluation has noPurely functional means that evaluation has no side-effects– a function maps input to output and does nothing else, a u ct o aps put to output a d does ot g e se,
just like a “real mathematical function”
Referential transparency: “equals can be substituted for equals”
can dis ega d o de and d plication of e al ation– can disregard order and duplication of evaluation
4343
Referential transparencyReferential transparencyReferential transparencyReferential transparency
Easier for the programmer (and the compiler) toEasier for the programmer (and the compiler) to reason about program behavior
E lExample:
f(x)*f(x)
always has the same behavior as
let z=f(x) in z*z
(which is not true for Java!)
4444
More about proving properties of programs later...
SummarySummarySummarySummary
Haskell is purely functionalHaskell is purely functionalRecursive data structuresPattern matchingHighe o de f nctionsHigher-order functionsStrong typingg yp g
4545
– advanced features in the next lecture ☺
top related