next up previous
Next: Polymorphic Types and Higher Up: Generalising Both Approaches Previous: Mutual recursion

Non-deterministic Skeletons

Algebraic types correspond to RUL programs, in which predicates are deterministic and only have a single argument. The stepwise enhancement paradigm has no such restriction, hence nondeterministic skeletons such as branch/1 (Program 2b) and connected/2 (Program 9) can be used.

connected(A, A).
connected(A0, A) :-
    edge(A0, A1),
    connected(A1, A).
Program 9: Transitive closure of the edge/2 relation

As noted in (Naish, [Nai96]), higher order logic programs can also be nondeterministic and nondeterministic analogues of foldr can be constructed. A version of foldr for paths in a graph was written (using considerable intellectual effort) based on the simple transitive closure procedure connected/2, above. The close relationship between ``shape'' and stepwise enhancement we have uncovered can be used to generalise the transformation from algebraic types (or RUL programs) to foldr functions. From an arbitrary skeleton (not necessarily a RUL program), we can generate an appropriate version of foldr as follows.

=1pc0 Definition 6.1.(foldr transformation) A procedure with A arguments and C clauses leads to a higher order procedure with C+A+1 arguments. It has C ``higher order'' arguments and one additional ``result'' argument. The recursive calls in the clause bodies have the same higher order arguments as the head and new variables for their results. Each clause also has an additional call/N with the higher order argument for that clause, the variables in the head which did not appear in any recursive body calls, result arguments of the body calls and the result argument of the head. If this call has only two arguments then call/2 is replaced by =/2 (the higher order argument is simply a term which is returned for the base case; the call to =/2 can then be optimised away, as in Program 7).

Mutual recursion can be treated in the same way. Each procedure in a set of (mutually recursive) procedures is transformed as above, where C is the number of clauses in the set of procedures. In the description of the transformation above and other transformations in Section 8 we refer to ``recursive'' calls. This should be interpreted as including mutual recursion when transforming multiple procedures. Our implementation of the tools introduced in Section 7 has been made more flexible by using an even more liberal definition: a call to any procedure defined in the input to the tool is considered recursive and C is the number of clauses defined in procedures indirectly called by a specified procedure.

For list/1 and tree/1 the results are the foldr/4 and foldrbt/4 definitions given in Programs 7 and 8. For branch/1 and connected/2 the results are in Program 10. The foldrcon/5 procedure here is actually more general than the manually constructed version (which had a base case of V=FB instead of call/3) and can be used in the applications described in (Naish, [Nai96]). Section 6.1 gives an example where a call is needed in the base case.

foldrb(FL, FR, FB, leaf(X), V) :-       
    call(FB, X, V).                    
foldrb(FL, FR, FB, t(L,R), V) :-      
    foldrb(FL, FR, FB, L, V1),       
    call(FL, R, V1, V).             
foldrb(FL, FR, FB, t(L,R), V) :-   
    foldrb(FL, FR, FB, R, V2),
    call(FR, L, V2, V).

foldrcon(FE, FB, A, A, V) :-
    call(FB, A, V).
foldrcon(FE, FB, A0, A, V) :-
    edge(A0, A1),
    foldrcon(FE, FB, A1, A, V1),
    call(FE, A0, V1, V).
Program 10: Nondeterministic foldr for branch and connected


next up previous
Next: Polymorphic Types and Higher Up: Generalising Both Approaches Previous: Mutual recursion
Lee Naish
2000-07-26