Skip to content

Commit 6f4dec5

Browse files
committed
add recursion notes
1 parent 0e580f4 commit 6f4dec5

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

Diff for: 13_recursive_functions.hs

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import Debug.Trace
2+
3+
-- * Recursion
4+
-- Recursion is when a function that calls itself until it reaches its solution.
5+
-- Anything that can be accomplished via iteration can be done using recursion.
6+
-- Haskell has only recursion, no looping.
7+
last' :: [a] -> a
8+
last' (x:[]) = x
9+
last' (x:xs) = last' xs
10+
11+
-- Failure in recursion
12+
-- Infinite recursion - If the recursive function does not have a proper termination condition or if the termination condition is not reached due to some logical error, the recursion can continue indefinitely, resulting in an infinite loop. This can cause the program to run out of memory or hang indefinitely.
13+
-- Stack overflow - Haskell uses a call stack to keep track of function calls. If the recursion goes too deep without proper termination, it can exhaust the call stack space, leading to a stack overflow error.
14+
-- Incorrect base case - If the base case(s) of the recursive function is not defined correctly, it can lead to unexpected behavior or incorrect results.
15+
-- Incorrect recursive call - If the recursive call within the function is not defined correctly or if the arguments passed to the recursive call are incorrect, it can lead to incorrect results or unexpected behavior.
16+
17+
-- Debug.Trace can be used to show the steps that the recursion takes. (Imported above).
18+
last'' :: [Int] -> Int
19+
last'' (x : []) = x
20+
last'' (x:xs) = trace ("xs = " ++ show xs) (last'' xs)
21+
traceLast = last'' [1..17]
22+
23+
-- * Factorial created using recursion in different control flow structures
24+
-- Factorial using pattern matching
25+
factorial :: Int -> Int
26+
factorial 0 = 1
27+
factorial 1 = 1
28+
factorial x = x * factorial (x - 1)
29+
30+
-- Factorial using guards
31+
factorial' :: Integer -> Integer
32+
factorial' n
33+
| n == 0 = 1
34+
| otherwise = n * factorial' (n - 1)
35+
36+
-- Factorial using case statement
37+
factorial'' :: Integer -> Integer
38+
factorial'' n = case (n > 0) of
39+
False -> 1
40+
True -> n * factorial'' (n - 1)
41+
42+
-- Factorial using if/then/else
43+
factorial''' :: Integer -> Integer
44+
factorial''' n = if n <= 0 then (1) else n * factorial''' (n - 1)
45+
46+
-- Safe factorial to cover negative numbers using if else
47+
safeFactorial :: Integer -> Integer
48+
safeFactorial 0 = 1
49+
safeFactorial n = if n < 0 then (-1) else n * safeFactorial (n - 1)
50+
51+
-- * Inductive vs Iterative recursion
52+
-- The problem will determine which one you use. Some problems lend themselves to inductive recursion. But sometimes iterative is needed.
53+
54+
-- Inductive recursion involves breaking down a problem into smaller subproblems and solving each subproblem recursively until a base case is reached.
55+
-- Factorial written like this is an example of inductive recursion.
56+
factorial_ind :: Int -> Int
57+
factorial_ind 0 = 1
58+
factorial_ind 1 = 1
59+
factorial_ind x = x * factorial (x - 1)
60+
61+
-- Iterative recursion involves solving a problem iteratively using a loop or iteration construct.
62+
-- Loops are not native to Haskell, but can be emulated
63+
-- Can be helpful because you can introduce an accumulator value where you 'store' a value
64+
-- Factorial can be written in an iterative way
65+
factorial_iter :: Int -> Int
66+
factorial_iter x = loop 1 1 where
67+
loop acc i
68+
| i > x = acc
69+
| otherwise = loop (acc * i) (i + 1)
70+
71+
-- * More Recursion Examples
72+
numList :: [Int]
73+
numList = [1..22]
74+
75+
length' :: [a] -> Int
76+
length' [] = 0
77+
length' list = 1 + length (tail list)
78+
79+
findLength = length' numList
80+
findStrLength = length' "Hello"
81+
82+
length'' :: [a] -> Int
83+
length'' [] = 0
84+
length'' (x:xs) = 1 + length'' xs
85+
86+
sum' :: [Int] -> Int
87+
sum' [] = 0
88+
sum' (x:xs) = x + sum' xs
89+
90+
-- Special pattern to split lists
91+
specialSum :: [Int] -> Int
92+
specialSum [] = 0
93+
specialSum [x] = x
94+
-- specialSum
95+
specialSum (x:y:zs) = y
96+
97+
-- Create a function that takes the sum of every two numbers in a list
98+
sumOf2 :: [Int] -> [Int]
99+
sumOf2 [] = []
100+
sumOf2 [x] = [x]
101+
sumOf2 (x:y:zs) = x + y : sumOf2 zs
102+
103+
example1 = sumOf2 [1]
104+
example2 = sumOf2 [1,2]
105+
example3 = sumOf2 [1..50]
106+
107+
-- Recursive function to add two to all
108+
-- (Int->Int) in this case is a function
109+
applyToAll :: (Int -> Int) -> [Int] -> [Int]
110+
applyToAll _ [] = []
111+
applyToAll f (x:xs) = (f x) : applyToAll f xs
112+
113+
addTwo = applyToAll (+2) [2,3,4,5]
114+
115+
multiplyByTwo = applyToAll (*2) [2,3,4,5]
116+
117+
map' :: (a -> b) -> [a] -> [b]
118+
map' _ [] = []
119+
map' f (x:xs) = f x : map f xs
120+
mapNums = map' (+10) [1,2,3,4]
121+
mapStrings = map' reverse ["hello", "good morning"]
122+
123+
filter' :: (a -> Bool) -> [a] -> [a]
124+
filter' _ [] = []
125+
filter' f (x:xs)
126+
| f x = x : filter' f xs
127+
| otherwise = filter' f xs
128+
129+
sum'' :: [Int] -> Int
130+
sum'' [] = 0
131+
sum'' (x:xs) = x + sum xs
132+
133+
listLength :: [a] -> Int
134+
listLength [] = 0
135+
listLength (x:xs) = 1 + listLength xs
136+
137+
addListInts :: [Int] -> Int
138+
addListInts [] = 0
139+
addListInts [x] = x
140+
addListInts (x:xs) = x + addListInts xs
141+
142+
reverse' :: [a] -> [a]
143+
reverse' [] = []
144+
reverse' (x:xs) = reverse' xs ++ [x]
145+
146+
take' :: Int -> [a] -> [a]
147+
take' 0 _ = []
148+
take' _ [] = []
149+
take' n xs = case xs of { x : xs -> x : take' (n - 1) xs }

0 commit comments

Comments
 (0)