# Comp202: Principles of Object-Oriented Programming II Fall 2006 -- Lecture #3: Higher Order Functions

• Abstraction of data movement in list processing: higher order functions.
• Review of the binary framework

## Abstraction of Data Movement

In many situations, processing a list involves processing the first element of a list (in the case of a non-empty list) and moving the result along the list structure in a sequential manner.  The previous two examples (reversing a list and concatenating two lists) illustrate two common data movements:

• forward accumulation - the data is moved and processed from the head of the list to the end of the list; for example, reversing a list.
• reverse accumulation - the data is moved and processed from the end of the list to the head of the list; for example, appending a list to another list.

These two common ways of list processing can be abstracted into

• an abstract function, ILambda, representing an abstract computation performed on each element of a list and
• a pair of "higher-order functions", Foldl and Foldr, representing the forward and reverse data movement respectively.

### Abstract function of a variable number of parameters

// NOTE the new variable arguments ("varargs") syntax in Java 5.0 here!

interface ILambda {
Object apply(Object... params);
}

#### Examples

1. Adding an open-ended number of Integer ogbjects.

2. "Consing" a list to form a new list.

`package fp;`
```/**
* @author DXN
*/
public class Add implements ILambda {
}
/**
* Adds zero to many Integer.
* @param params Integer[].
* @return Integer
*/
public Object apply(Object ... params) {
// params is treated as Object[].
//  Integer[] p = (Integer[])params; // Not allowed in Java: Class Cast Exception!
int sum = 0;
// New Java 5.0 for loop:
for (Object i: params) {
sum += (Integer)i;  // auto-unboxing: ((Integer)i).intValue()
}
//        Traditional for loop (works OK):
//        for(int i = 0; i < params.length; i++) {
//            sum += (Integer)params[i];
//        }
return sum;  // auto-boxing: new Integer(sum)
}
}```
`package fp;`
```import listFW.*;
import listFW.factory.*;```
```/**
* Makes new NEList given a first and rest.
* @author DXN
*/
public class Cons implements ILambda {
private IListFactory _fac;
public Cons(IListFactory fac) {
_fac = fac;
}
/**
* Creates an INEList with a given first and rest.
* @param params[0] the first element of the IList to be created.
* @param params[1] IList, the rest of the IList to be created.
* @return INEList
*/
public Object apply(Object... params) {
return _fac.makeNEList(params[0], (IList)params[1]);
}
}```

### Forward Accumulation Visitor: Foldl "fold left"

Uses an ILambda to process a list from front to end.

Functional definition:

• empty case: foldl(empty, f, b) = b;
• non-empty case: foldl(host, f, b) = foldl(host.rest, f, f(host.first, b));
 IList (Immutable List) LRStruct (Mutable list) public class FoldlIList implements IListAlgo {     private ILambda2 _f;     public FoldlIList(ILambda f) {         _f = f;     } public class FoldlLRS implements IAlgo {    private ILambda2 _f;     public FoldlLRS(ILambda f) {         _f = f;     } // empty case: in class exercise public Object emptyCase(IMTList h, Object b) {     return b; } // empty case: in class exercise public Object emptyCase(LRStruct h, Object b) { } // non-empty case: in class exercise public Object emptyCase(INEList h, Object b) {   return h.getRest().execute(this, _f.apply(h.getFirst(), b)); }} // non-empty case: in class exercise public Object emptyCase(LRStruct h, Object b) { }}

### Reverse Accumulation Visitor: Foldr "fold right"

Uses an ILambda to process a list from end to front.

Functional definition:

• empty case: foldr(empty, f, b) = b;
• non-empty case: foldr(host, f, b) = f(host.first, foldr(host.rest, f, b));
 IList (Immutable List) LRStruct (Mutable list) public class FoldrIList implements IListAlgo {     private ILambda2 _f;     public FoldrIList(ILambda f) {         _f = f;     } public class FoldrLRS implements IAlgo {    private ILambda2 _f;     public FoldrLRS(ILambda f) {         _f = f;     } // empty case: in class exercise public Object emptyCase(IMTList h, Object b) { } // empty case: in class exercise public Object emptyCase(LRStruct h, Object b) { } // non-empty case: in class exercise public Object emptyCase(INEList h, Object b) { }} // non-empty case: in class exercise public Object emptyCase(LRStruct h, Object b) { }}

### Food for thoughts: Rewrite Reverse and Append using Foldl and/or Foldr

Study the following JUnit test code to see how reversing a list is done using Foldl.

```package listFW.test;
import junit.framework.TestCase;```
```import listFW.*;
import listFW.visitor.*;
import listFW.factory.*;
import fp.*;```
```/**
* Testing reversing a list using Foldl.
* @author DXN
*/
public class Test_Foldl extends TestCase {
IListFactory fac = CompositeListFactory.Singleton;
ILambda cons = new Cons(fac);
IListAlgo algo = new Foldl(cons);
IList mt = fac.makeEmptyList();
```
```    public void testEmpty() {
assertEquals("Reverse Empty list", "()", mt.execute(algo, mt).toString());
}
```
```    public void testNonEmpty() {
IList L = fac.makeNEList("a", mt);
assertEquals("Reverse (a)", "(a)", L.execute(algo, mt).toString());
L = fac.makeNEList("b", L);
assertEquals("Reverse ( b, a)", "(a, b)", L.execute(algo, mt).toString());
L = fac.makeNEList("c", L);
assertEquals("Reverse ( c, b, a)", "(a, b, c)", L.execute(algo, mt).toString());
}
}```

As one can see from the above, to reverse a list, all we have to do is fold left using "cons" as the processing function.

We leave it as an exercise to concatenate two lists using an appropriate fold operation together with an appropriate ILambda.

## Mutable Binary Tree Framework

The Mutable Binary Tree Framework Store data in a hierarchical fashion; mutation is allowed

• Source code
• UML and documentation
• Key Design Patterns:
• The Composite Pattern: for implementing the structure
• The Visitor Pattern: for decoupling the algorithms on the structure from the structure itself
• The State Pattern: for implementing dynamic re-classification, allowing transparent state dependent behavioral changes.

Last Revised Thursday, 03-Jun-2010 09:52:24 CDT

©2006 Stephen Wong and Dung Nguyen