functional programming - recursion
DESCRIPTION
Recursion, tail recursion.TRANSCRIPT
![Page 1: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/1.jpg)
Functional ProgrammingRecursion
H. Turgut Uyar
2013-2015
![Page 2: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/2.jpg)
License
© 2013-2015 H. Turgut Uyar
You are free to:
Share – copy and redistribute the material in any medium or format
Adapt – remix, transform, and build upon the material
Under the following terms:
Attribution – You must give appropriate credit, provide a link to the license, andindicate if changes were made.
NonCommercial – You may not use the material for commercial purposes.
ShareAlike – If you remix, transform, or build upon the material, you mustdistribute your contributions under the same license as the original.
For more information:https://creativecommons.org/licenses/by-nc-sa/4.0/
Read the full license:
https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
![Page 3: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/3.jpg)
Topics
1 FunctionsInfix - PrefixGuardsErrors
2 RecursionPrimitive RecursionTail RecursionTree RecursionExamples
![Page 4: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/4.jpg)
Topics
1 FunctionsInfix - PrefixGuardsErrors
2 RecursionPrimitive RecursionTail RecursionTree RecursionExamples
![Page 5: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/5.jpg)
Infix - Prefix
functions infix when in backquotes
mod n 2n ‘mod‘ 2
operators prefix when in parentheses
6 * 7(*) 6 7
![Page 6: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/6.jpg)
Infix - Prefix
functions infix when in backquotes
mod n 2n ‘mod‘ 2
operators prefix when in parentheses
6 * 7(*) 6 7
![Page 7: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/7.jpg)
Topics
1 FunctionsInfix - PrefixGuardsErrors
2 RecursionPrimitive RecursionTail RecursionTree RecursionExamples
![Page 8: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/8.jpg)
Guards
writing conditional expressions can become complicated
guards: predicates to check cases
n :: t1 -> t2 -> ... -> tk -> tn x1 x2 ... xk| p1 = e1| p2 = e2...
| otherwise = e
function result is the expression for the first satisfied predicate
![Page 9: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/9.jpg)
Guard Example
maximum of three integers
maxThree :: Integer -> Integer -> Integer -> IntegermaxThree x y z| x>=y && x>=z = x| y>=z = y| otherwise = z
![Page 10: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/10.jpg)
Topics
1 FunctionsInfix - PrefixGuardsErrors
2 RecursionPrimitive RecursionTail RecursionTree RecursionExamples
![Page 11: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/11.jpg)
Errors
errors can be reported using error
doesn’t change the type signature
example: reciprocal (multiplicative inverse)
reciprocal :: Float -> Floatreciprocal x| x == 0 = error "division by zero"| otherwise = 1.0 / x
![Page 12: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/12.jpg)
Topics
1 FunctionsInfix - PrefixGuardsErrors
2 RecursionPrimitive RecursionTail RecursionTree RecursionExamples
![Page 13: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/13.jpg)
Recursion Examples
greatest common divisor
gcd :: Integer -> Integer -> Integergcd x y = if y == 0 then x else gcd y (x ‘mod‘ y)
factorial
fac :: Integer -> Integerfac n| n < 0 = error "negative parameter"| n == 0 = 1| otherwise = n * fac (n - 1)
![Page 14: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/14.jpg)
Recursion Examples
greatest common divisor
gcd :: Integer -> Integer -> Integergcd x y = if y == 0 then x else gcd y (x ‘mod‘ y)
factorial
fac :: Integer -> Integerfac n| n < 0 = error "negative parameter"| n == 0 = 1| otherwise = n * fac (n - 1)
![Page 15: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/15.jpg)
Stack Frame Example
gcd x y = if y == 0 then x else gcd y (x ‘mod‘ y)
gcd 9702 945~> gcd 945 252
~> gcd 252 189~> gcd 189 63
~> gcd 63 0~> 63
~> 63~> 63
~> 63~> 63
![Page 16: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/16.jpg)
Stack Frame Example
fac n| n < 0 = error "negative parameter"| n == 0 = 1| otherwise = n * fac (n - 1)
fac 4~> 4 * fac 3
~> 3 * fac 2~> 2 * fac 1
~> 1 * fac 0~> 1
~> 1~> 2
~> 6~> 24
![Page 17: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/17.jpg)
Topics
1 FunctionsInfix - PrefixGuardsErrors
2 RecursionPrimitive RecursionTail RecursionTree RecursionExamples
![Page 18: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/18.jpg)
Tail Recursion
if the result of the recursive call is also the result of the caller,then the function is said to be tail recursive
the recursive function call is the last action:nothing left for the caller to do
no need to keep the stack frame around:reuse the frame of the caller
![Page 19: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/19.jpg)
Tail Recursion
if the result of the recursive call is also the result of the caller,then the function is said to be tail recursive
the recursive function call is the last action:nothing left for the caller to do
no need to keep the stack frame around:reuse the frame of the caller
![Page 20: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/20.jpg)
Stack Frame Example
gcd x y = if y == 0 then x else gcd y (x ‘mod‘ y)
gcd 9702 945~> gcd 945 252~> gcd 252 189~> gcd 189 63~> gcd 63 0~> 63
![Page 21: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/21.jpg)
Tail Recursion
to rearrange a function to be tail recursive:
define a helper function that takes an accumulator
base case: return accumulator
recursive case: make recursive call with new accumulator value
![Page 22: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/22.jpg)
Tail Recursion Example
tail recursive factorial
facIter :: Integer -> Integer -> IntegerfacIter acc n| n < 0 = error "negative parameter"| n == 0 = acc| otherwise = facIter (acc * n) (n - 1)
fac :: Integer -> Integerfac n = facIter 1 n
![Page 23: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/23.jpg)
Stack Frame Example
facIter acc n| n < 0 = error "negative parameter"| n == 0 = acc| otherwise = facIter (acc * n) (n - 1)
fac 4~> facIter 1 4
~> facIter 4 3~> facIter 12 2~> facIter 24 1~> facIter 24 0~> 24
~> 24
![Page 24: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/24.jpg)
Tail Recursion Example
helper function can be local
negativity check only once
fac :: Integer -> Integerfac n| n < 0 = error "negative parameter"| otherwise = facIter 1 n
wherefacIter :: Integer -> Integer -> IntegerfacIter acc n’| n’ == 0 = acc| otherwise = facIter (acc * n’) (n’ - 1)
![Page 25: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/25.jpg)
Topics
1 FunctionsInfix - PrefixGuardsErrors
2 RecursionPrimitive RecursionTail RecursionTree RecursionExamples
![Page 26: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/26.jpg)
Tree Recursion
Fibonacci sequence
fibn =
1 if n = 1
1 if n = 2
fibn−2 + fibn−1 if n > 2
fib :: Integer -> Integerfib n| n == 1 = 1| n == 2 = 1| otherwise = fib (n - 2) + fib (n - 1)
![Page 27: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/27.jpg)
Stack Frame Example
![Page 28: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/28.jpg)
Topics
1 FunctionsInfix - PrefixGuardsErrors
2 RecursionPrimitive RecursionTail RecursionTree RecursionExamples
![Page 29: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/29.jpg)
Exponentiation
pow :: Integer -> Integer -> Integerpow x y| y == 0 = 1| otherwise = x * pow x (y - 1)
use the following definition:
xy =
1 if y = 0
(xy/2)2
if y is even
x · xy−1 if y is odd
![Page 30: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/30.jpg)
Exponentiation
pow :: Integer -> Integer -> Integerpow x y| y == 0 = 1| otherwise = x * pow x (y - 1)
use the following definition:
xy =
1 if y = 0
(xy/2)2
if y is even
x · xy−1 if y is odd
![Page 31: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/31.jpg)
Fast Exponentiation
pow :: Integer -> Integer -> Integerpow x y| y == 0 = 1| even y = sqr (pow x (y ‘div‘ 2))| otherwise = x * pow x (y - 1)wheresqr :: Integer -> Integersqr n = n * n
![Page 32: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/32.jpg)
Square Roots with Newton’s Method
start with an initial guess y (say y = 1)
repeatedly improve the guess by taking the mean of y and x/y
until the guess is good enough (√
x ·√
x = x)
example:√
2
y x/y next guess1 2 / 1 = 2 1.51.5 2 / 1.5 = 1.333 1.41671.4167 2 / 1.4167 = 1.4118 1.41421.4142 ... ...
![Page 33: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/33.jpg)
Square Roots with Newton’s Method
newton :: Float -> Float -> Floatnewton guess x| isGoodEnough guess x = guess| otherwise = newton (improve guess x) x
isGoodEnough :: Float -> Float -> BoolisGoodEnough guess x = abs (guess*guess - x) < 0.001
improve :: Float -> Float -> Floatimprove guess x = (guess + x/guess) / 2.0
sqrt :: Float -> Floatsqrt x = newton 1.0 x
![Page 34: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/34.jpg)
Square Roots with Newton’s Method
newton :: Float -> Float -> Floatnewton guess x| isGoodEnough guess x = guess| otherwise = newton (improve guess x) x
isGoodEnough :: Float -> Float -> BoolisGoodEnough guess x = abs (guess*guess - x) < 0.001
improve :: Float -> Float -> Floatimprove guess x = (guess + x/guess) / 2.0
sqrt :: Float -> Floatsqrt x = newton 1.0 x
![Page 35: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/35.jpg)
Square Roots with Newton’s Method
newton :: Float -> Float -> Floatnewton guess x| isGoodEnough guess x = guess| otherwise = newton (improve guess x) x
isGoodEnough :: Float -> Float -> BoolisGoodEnough guess x = abs (guess*guess - x) < 0.001
improve :: Float -> Float -> Floatimprove guess x = (guess + x/guess) / 2.0
sqrt :: Float -> Floatsqrt x = newton 1.0 x
![Page 36: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/36.jpg)
Square Roots with Newton’s Method
newton :: Float -> Float -> Floatnewton guess x| isGoodEnough guess x = guess| otherwise = newton (improve guess x) x
isGoodEnough :: Float -> Float -> BoolisGoodEnough guess x = abs (guess*guess - x) < 0.001
improve :: Float -> Float -> Floatimprove guess x = (guess + x/guess) / 2.0
sqrt :: Float -> Floatsqrt x = newton 1.0 x
![Page 37: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/37.jpg)
Square Roots with Newton’s Method
sqrt :: Float -> Floatsqrt x = newton 1.0 xwherenewton :: Float -> Float -> Floatnewton guess x’| isGoodEnough guess x’ = guess| otherwise = newton (improve guess x’) x’
isGoodEnough :: Float -> Float -> BoolisGoodEnough guess x’ =
abs (guess*guess - x’) < 0.001
improve :: Float -> Float -> Floatimprove guess x’ = (guess + x’/guess) / 2.0
![Page 38: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/38.jpg)
Square Roots with Newton’s Method
doesn’t work with too small and too large numbers (why?)
isGoodEnough guess x’ =(abs (guess*guess - x’)) / x’ < 0.001
![Page 39: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/39.jpg)
Square Roots with Newton’s Method
no need to pass x around, it’s already in scope
sqrt x = newton 1.0wherenewton :: Float -> Floatnewton guess| isGoodEnough guess = guess| otherwise = newton (improve guess)
isGoodEnough :: Float -> BoolisGoodEnough guess =
(abs (guess*guess - x)) / x < 0.001
improve :: Float -> Floatimprove guess = (guess + x/guess) / 2.0
![Page 40: Functional Programming - Recursion](https://reader033.vdocuments.us/reader033/viewer/2022052619/5562ebedd8b42ad26c8b50b0/html5/thumbnails/40.jpg)
References
Required Reading: ThompsonChapter 3: Basic types and definitions
Chapter 4: Designing and writing programs