How do I create a predicate that takes another predicate and returns a derived version of it?
For example, pairwise predicates can be fairly mechanically extended to apply to lists:
all_whatever(_, []).
all_whatever(X, [Y|T]) :-
whatever(X, Y),
all_whatever(X, T).
What would be the definition of
pairwise_listwise(whatever, all_whatever).
If it's not possible/common/clunky/violates principles, what would be the alternative pattern?
There are two different ways to achieve what you want. The simplest, and likely preferred, way is to define a meta-predicate that takes any binary predicate and applies it to all elements of the list like so:
You can then call this as
listwise(whatever, Y1, Xs1)to applywhatevertoY1and each element ofXs1.This is made possible thanks to the
call/Nmeta-predicate. Note that this meta-predicate can also take partially constructed goals as first argument, so that an alternative formulation could be:Which is then called as
listwise(whatever(Y1),Xs1). This version of the predicate is actually known asmaplist/2instead oflistwise, at least in SWI-Prolog (in modulelibrary(apply)) and SICStus Prolog (in modulelibrary(lists)).The second way to achieve what you want (actually closer to what you where asking for) is to actually define a new predicate
all_whatever/2using term expansion. Term expansion is a mechanism to rewrite terms when they are loaded (see e.g. for more details in SWI-Prolog: https://www.swi-prolog.org/pldoc/doc_for?object=term_expansion/2). I am showing here the SWI-Prolog version, which is by defining a clause for theterm_expansion/2predicate. This mechanism works differently in different systems or is altogether missing.In this clause,
ExpandedTermis a list defining the two clauses we want to define and all the terms in it are built from the predicate names using=... One can then define the new predicate as follows:When this code is loaded, that clause will be expanded and replaced by two clauses defining the new predicate
all_whatever. And now one can call for instanceall_whatever(Y1,Xs1).My preference goes to the first approach (conceptually simpler and works across Prolog versions) but I think it is also useful to be aware of the existence of the term expansion mechanism as well.