More recursive functions
my-sum
and the program directory
We talked about how the my-sum
function we wrote last class executes. See
lecture capture for details.
Recursion
- Recursion
- When a function or computation calls itself
Recursion can be tricky to understand, but it’s extremely useful. We’ve talked a lot about writing solutions that use the structure of the problem. Recursion lets us do this for many problems–any time the problem is structured such that the solution on larger inputs can be built from the solution on smaller inputs, recursion is appropriate.
The any-below-10
function
Let’s work on another function over lists of numbers. any-below-10
should
return true if any member of the list is less than 10, and false
otherwise. We’ve seen one way of writing it:
fun any-below-10(lst :: List<Number>) -> Boolean: any(lam(x): x < 10 end, lst) end
This will work fine, but let’s try to write it with cases
. Once we’ve done
that, we’ll be able to see how all
is actually implemented!
As we did with my-sum
, we’ll start with some tests:
fun any-below-10(lst :: List<Number>) -> Boolean: ... where: any-below-10([list: 3, 1, 4]) is (3 < 10) or (1 < 10) or (4 < 10) any-below-10([list: 1, 4]) is (1 < 10) or (4 < 10) any-below-10([list: 4]) is (4 < 10) any-below-10([list: ]) is ... end
What should go in that last case? Are any of the numbers in an empty list below
10? No! So, let’s put false
.
We can rewrite these tests again:
fun any-below-10(lst :: List<Number>) -> Boolean: ... where: any-below-10([list: 3, 1, 4]) is (3 < 10) or any-below-10([list: 1, 4]) any-below-10([list: 1, 4]) is (1 < 10) or any-below-10([list: 4]) any-below-10([list: 4]) is (4 < 10) or any-below-10([list: ]) any-below-10([list: ]) is false end
This suggests what our function body should look like:
fun any-below-10(lst :: List<Number>) -> Boolean: cases (List) lst: | empty => false | link(fst, rst) => (fst < 10) or any-below-10(rst) end where: any-below-10([list: 3, 1, 4]) is (3 < 10) or any-below-10([list: 1, 4]) any-below-10([list: 1, 4]) is (1 < 10) or any-below-10([list: 4]) any-below-10([list: 4]) is (4 < 10) or any-below-10([list: ]) any-below-10([list: ]) is false end
Now that we’ve seen how this works, we can see how any
is implemented: it’s
exactly the same, except that it applies some particular function instead of
just checking if numbers are less than 10:
fun my-any(f, lst :: List) -> Boolean: cases (List) lst: | empty => false | link(fst, rst) => f(fst) or my-any(f, rst) end end
Striped flags
We did a lecture activity about a function to create flags with horizontal stripes. See the lecture capture for details! We ended up with this code:
include image fun striped-flag(colors :: List<String>) -> Image: doc: "produce a flag with horizontal stripes" cases (List) colors: | empty => empty-image | link(color, rest) => stripe = rectangle(120, 30, "solid", color) above(stripe, striped-flag(rest)) end end