next up previous
Next: You'll Take the High Up: Stepwise Enhancement and Higher Previous: A Higher Order Approach

Incorporating Shape

Recent work on shape (Jay and Cockett, [JC94]), (Jay, [Jay95]), (Bellé et al., [BJM96]) and polytypism (Jeuring and Jansson, [JJ96]), (Jansson and Jeuring, [JJ96]) has formalised the notion that many data types have certain higher order functions naturally associated with them. For example, map/3 takes a list and produces another list of the same length. The shape of the output, the list structure, is the same as the shape of the input and the elements of the lists are related by the function map/3 applies. The idea of map/3 can be applied to any algebraic type such as lists and trees, and also arrays and matrices. A generic version of map/3 applied to a binary tree will produce a binary tree of the same shape where the elements of the trees are related by the function map/3 applies.

Similarly, foldr can be generalised to any algebraic type. For lists, a call to foldr specifies two things: what should be returned for the empty list, and what should be returned for a non-empty list, given the head and the result of folding the tail. For a general algebraic type we need to specify what should be returned for each constructor in the type, given the arguments of the constructor corresponding to type parameters and the result of folding the arguments which correspond to a concrete type (generally the type being defined recursively).

Consider the prod_leaves/2 example given earlier as Program 3a. The overall operation is to fold a tree into a single number. We need to define the results of folding terms of the form leaf(X) and tree(L,R), given the folded versions of L and R.

Reconstructing the predicate is_tree/1 as a definition of the type bt(T) and using the approach of (Naish, [Nai96]) we arrive at Program 8: a version of foldr for this tree type and corresponding definitions of prod_leaves/2 and sum_leaves/2. In (Naish, [Nai96]) it was assumed that foldrbt/4 would be written by a programmer who has the required degree of insight. It is now clear that this predicate can be generated automatically from a definition of the type. This is discussed in Section 6.

:- type bt(T) ---> leaf(T) ; tree(bt(T),bt(T)).

foldrbt(TreeP, LeafP, leaf(X), Folded) :-
    call(LeafP, X, Folded).
foldrbt(TreeP, LeafP, tree(L, R), Folded) :-
    foldrbt(TreeP, LeafP, L, FoldedL),
    foldrbt(TreeP, LeafP, R, FoldedR),
    call(TreeP, FoldedL, FoldedR, Folded).

prod_leaves(T, P) :- foldrbt(times, =, T, P).
sum_leaves(T, P) :- foldrbt(plus, =, T, P).
Program 8: Extensions of Program 2a using foldr


next up previous
Next: You'll Take the High Up: Stepwise Enhancement and Higher Previous: A Higher Order Approach
Lee Naish
2000-07-26