Today, we talked about higher-order functions, which also are also called lambdas and commands. Initially, I presented the code for Reverse
and Append
from last lecture again. Then I added other things that you can do to the mix, such as generating a string representation, adding numbers or dividing them. The latter is important, because division is not commutative. I asked the students what is different between these operations and what is the same.
We came to realize that, depending on whether they use forward or backward accumulation, they all follow the same structure. In forward accumulation, they start with an initial value, perform some kind of operation with the initial value and the first of the list, then recur into the rest, using the result of the operation as initial value for the next level of recursion. In backward accumulation, they start with an initial value that is passed all the way to the end of the list. Then, for the empty list, that initial value is returned, and on the way out of the recursion, for each non-empty list, an operation is performed with the first of the list and the return value of the recursion that just finished, and the result is returned to the next level outward.
I then showed this in a more mathematical way, using a binary function f(x, y), and how forward accumulation yields f(f(f(f(i, l1), l2), l3), l4) for forward accumulation and f(l1, f(l2, f(l3, f(l4, i)))) for backward accumulation.
Unfortunately, I had written out our sample list from left to right, beginning with the empty list, as “empty-1-2-3”, instead of “1, 2, 3”, and that caused me to confuse fold left and fold right.
Another small problem occurred during the discussion of lambdas, the way we implement these different operations. The lecture notes provided code for an Add
lambda. In fold left and fold right, the lambdas are binary; however, Add
could process an arbitrary number of parameters. It would even add zero or one numbers. I wanted this to be exactly two — I should have previewed the lecture notes better, beyond the point of checking what code is there, but also precisely what it does. Fortunately, the Cons
lambda was binary.
After we had discussed lambdas and worked out the code for FoldL
and FoldR
, we talked about how to do Reverse
and Append
using fold left and fold right, respectively. We arrived at the interesting result that the operations for both algorithms are the same!
new ILambda() {
public Object apply(Object... params) {
return new NEList(params[0], ((IList)params[1]);
}
}
The two things that differ between Reverse
and Append
is that they fold in different directions, and that they use different initial values (empy list and the list to append, respectively).
I thought the material was interesting today, and my motivation and the general arc through the lecture was good, but it was marred by the two mistakes, mostly confusing fold left and fold right.