PLOGHELP HIGHER_ORDER Simon Nichols, May 1992 A library which defines some higher-order predicates. ?- library(higher_order). CONTENTS - (Use g to access required sections) -- Introduction -- Operations on Lists -- ... maplist(+Pred, +Xs) -- ... maplist(+Pred, +Xs, ?Ys) -- ... reduce(+Pred, +Xs, ?Answer) -- Operations on Terms -- ... mapargs(+Pred, +Term) -- ... mapargs(+Pred, +Term1, ?Term2) -- Introduction ------------------------------------------------------- For practical purposes, a higher-order predicate is one which takes as arguments a predicate and some data, and applies the predicate to the data or (more usually) to components of the data. This can be done efficiently in Poplog Prolog using the call/N family of predicates (see PLOGHELP * CALL) which are the basis of the predicates defined in library(higher_order). -- Operations on Lists ------------------------------------------------ Each of the following operations applies a predicate to successive elements from a list or lists. The use of maplist/2 and maplist/3 in particular situations often removes the necessity of writing a special purpose recursive predicate to process the elements of a list. -- ... maplist(+Pred, +Xs) -------------------------------------------- is true when Pred(X) is true for each element X in the list Xs. For example: to determine whether each number in a list of numbers is odd we need only write a predicate which tests whether a single number is odd: odd(X) :- 1 is X mod 2. ?- maplist(odd, [1,3,5,7,9]). yes Used in this way, maplist/1 is equivalent to the function all or every provided by most functional languages, Another example: printing a string (list of character codes): ?- maplist(put, "Hello world"), nl. Hello world yes Used like this, maplist/1 is equivalent to the Lisp function MAPC and the Pop11 procedure applist. -- ... maplist(+Pred, +Xs, ?Ys) --------------------------------------- is true when Pred(X, Y) is true for each corresponding element X in the list Xs and Y in the list Ys. "Corresponding" means X and Y have the same index (position) in their respective lists. This is commonly used to derive a new list Ys obtained by applying Pred to each element X of Xs. For example, given a list of numbers we can create a new list in which each element is double the corresponding element from the original list as follows: double(X, Y) :- Y is 2*X. ?- maplist(double, [2,3,4,5], X). X = [4, 6, 8, 10] ? yes This usage is equivalent to the classic map function of functional languages, Lisp's MAPCAR and the Pop11 procedure maplist. -- ... reduce(+Pred, +Xs, ?Answer) ------------------------------------ is true when Pred(X0, [], Answer0) is true and Pred(XI, AnswerI-1, AnswerI) is true for all I where 0 < I < N and XI is the Ith element of Xs. In procedural terms, Pred is initially applied to the head of the list and the empty list, yielding Answer0. Pred will then be applied to the second element of the list (if there is one) and Answer0 (the result from the previous application of Pred), yielding Answer1. The process is repeated, applying Pred to each subsequent list element and the result of the previous application. This description assumes a call of reduce/3 with Answer unbound, as an output argument. For example, to find the sum of all the numbers in a list of numbers: add(X,Y,Z) :- Z is X+Y. ?- reduce(add, [1,2,3,4,5], X). X = 15 yes To find the largest number in a list of numbers: max(X, Y, X) :- X >= Y. max(X, Y, Y) :- X < Y. ?- reduce(max, [2,8,3,7,4], X). X = 8 yes -- Operations on Terms ------------------------------------------------ Each of the following operations applies a predicate to successive arguments from a term or terms. In any particular situation, their use removes the necessity of writing a special purpose recursive predicate to process the arguments of a term, making use of functor/3 and arg/3. -- ... mapargs(+Pred, +Term) ------------------------------------------ is true when Pred(Arg) is true for each argument Arg of Term. A good example of the use of mapargs/2 is the definition ground/1, which is true if its argument is ground (a term which contains no variables): ground(X) :- nonvar(X), mapargs(ground, X). ?- ground(f(g(x,y))). yes ?- ground(f(g(x,Y))). no Note that it is quite in order for mapargs/2 (and mapargs/3) to be given an atom as the first argument, since an atom is equivalent to a compound term with no arguments. -- ... mapargs(+Pred, +Term1, ?Term2) --------------------------------- is true when Pred(Arg1, Arg2) is true for the Ith argument Arg1 of Term1 and the Ith argument Arg2 of Term2, where Term1 and Term2 have the same functor and 1 <= I <= arity of each term. As an example, the predicate simplify/2 applies the rules x+0=x and 0+x=x to simplify an algebraic expression (where variables are represented by Prolog atoms): simplify(X+0, Y) :- simplify(X, Y). simplify(0+X, Y) :- simplify(X, Y). simplify(X, Y) :- mapargs(simplify, X, Y). ?- simplify(a*b+0-c*d+0, X). X = a * b - c * d ? yes Without mapargs/3, the definition of simplify/2 would be much longer and would involve a subsidiary predicate to process arguments and two calls each to functor/3 and arg/3. --- C.all/plog/help/higher_order --- Copyright University of Sussex 1992. All rights reserved. ----------