Why doesn't maplist/3 use a template? - prolog

The maplist/3 predicate has the following form
maplist(:Goal, ?List1, ?List2)
However the very similar function findall/3 has the form
findall(+Template, :Goal, -Bag)
Not only does it have a goal but a template as well. I've found this template to be quite useful in a number of places and began to wonder why maplist/3 doesn't have one.
Why doesn't maplist/3 have a template argument while findall/3 does? What is the salient difference between these predicates?

Templates as in findall/3, setof/3, and bagof/3 are an attempt to simulate proper quantifications with Prolog's variables. Most of the time (and here in all three cases) they involve explicit copying of those terms within the template.
For maplist/3 such mechanisms are not always necessary since the actual quantification is here about the lists' elements only. Commonly, no further modification happens. Instead of using templates, the first argument of maplist/3 is an incomplete goal that lacks two further arguments.
maplist(Goal_2, Xs, Ys).
If you insist, you can get exactly your template version using library(lambda):
templmaplist(Template1, Template2, Goal_0, Xs, Ys) :-
maplist(\Template1^Template2^Goal_0, Xs, Ys).
(Note that I avoid calling this maplist/5, since this is already defined with another meaning)
In general, I rather avoid making "my own templates" since this leads so easily to misunderstandings (already between me and me): The arguments are not the pure relational arguments one is usually expecting. By using (\)/1 instead, the local variables are somewhat better handled and more visible as being special.
... ah, and there is another good reason to rather avoid templates: They actually force you to always take into account some less-than-truly-pure mechanism as copying. This means that your program may expose some anomalies w.r.t. monotonicity. You really have to look into the very details.
On the other hand without templates, as long as there is no copying involved, even your higher-order predicates will maintain monotonicity like a charm.

Considering your concrete example will make clear why a template is not needed for maplist/3:
In maplist/N and other higher-order predicates, you can use currying to fix a particular argument.
For example, you can write the predicate:
p(Z, X, Y) :-
Z #= X + Y.
And now your example works exactly as expected without the need for a template:
?- maplist(p(1), [1,2,3,4], [0,-1,-2,-3]).
true.
You can use library(lambda) to dynamically reorder arguments, to make this even more flexible.

What is the salient difference between these predicates?
findall/3 (and family, setof/3 and bagof/3) cannot be implemented in pure Prolog (the monotonic subset without side effects), while maplist/N is simply a kind of 'macro', implementing boilerplate list(s) visit.
In maplist/N nothing is assumed about the determinacy of the predicate, since the execution flow is controlled by the list(s) pattern(s). findall/3 it's a list constructor, and it's essential the goal terminate, and (I see) a necessity to indicate what to retain of every succeeded goal invocation.

Related

Functional patterns in Prolog

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:
listwise(_,_,[]).
listwise(P,Y,[X|Xs]) :-
call(P,Y,X),
listwise(P,Y,Xs).
You can then call this as listwise(whatever, Y1, Xs1) to apply whatever to Y1 and each element of Xs1.
This is made possible thanks to the call/N meta-predicate. Note that this meta-predicate can also take partially constructed goals as first argument, so that an alternative formulation could be:
listwise(_,[]).
listwise(P,[X|Xs]) :-
call(P,X),
listwise(P,Xs).
Which is then called as listwise(whatever(Y1),Xs1). This version of the predicate is actually known as maplist/2 instead of listwise, at least in SWI-Prolog (in module library(apply)) and SICStus Prolog (in module library(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/2 using 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 the term_expansion/2 predicate. This mechanism works differently in different systems or is altogether missing.
term_expansion(pairwise_listwise(PairPred,ListPred), ExpandedTerm) :-
TerminalCall =.. [ListPred,_,[]],
RecursiveCall =.. [ListPred,Y,[X|Xs]],
SingleCall =.. [PairPred,Y,X],
FinalCall =.. [ListPred,Y,Xs],
ExpandedTerm = [TerminalCall, (RecursiveCall :- (SingleCall, FinalCall))].
In this clause, ExpandedTerm is 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:
pairwise_listwise(whatever, all_whatever).
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 instance all_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.

The reverse of applying a lambda expression, eta+alfa conversion in Prolog?

There are several interesting problems with co-routing. For example we want to reclaim unreached frozen goals. But there is a problem for Prolog systems that don't support cyclic terms. Namely a freeze:
?- freeze(V, p(...V...)).
leads to a loop in the internal data structure. A simple workaround would be currying the frozen goal. Thus instead of working with a predicate freeze/2, we would work with a predicate guard/2, which could be defined as follows:
guard(V, C) :- freeze(V, call(C, V)).
But how could we define freeze/2 in terms of guard/2? The obvious definition doesn't work, since it doesn't introduce a new variable, and we still have the problem that the closure contains V (assuming a lambda library where (\)/2 is the lambda abstraction):
freeze(V, G) :- guard(V, V\G).
Bye

Term-expansion workflows

I'm adding library support for common term-expansion workflows (1). Currently, I have defined a "set" workflow, where sets of term-expansion rules (2) are tried until one of them succeeds, and a "pipeline" workflow, where expansion results from a set of term-expansion rules are passed to the next set in the pipeline. I wonder if there are other sensible term-expansion workflows that, even if less common, have practical uses and are thus still worth of library support.
(1) For Logtalk, the current versions can be found at:
https://github.com/LogtalkDotOrg/logtalk3/blob/master/library/hook_pipeline.lgt
https://github.com/LogtalkDotOrg/logtalk3/blob/master/library/hook_set.lgt
(2) A set of expansion rules is to be understood in this context as a set of clauses for the term_expansion/2 user-defined hook predicate (also possibly the goal_expansion/2 user-defined hook predicate, although this is less likely given the fixed point semantics used for goal-expansion) defined in a Prolog module or a Logtalk object (other than the user pseudo-module/object).
The fixpoint is both already a set and a pipeline on a certain level during expansion. Its expand_term/2 is just the transitive closure of the one step term_expansion/2 clauses. But this works only during decending into a term, in my opinion we also need something when assembling the term again.
In rare cases this transitive closure even needs the (==)/2 check as is found in some Prolog systems. Most likely it can simply stop if none of the term_expansions/2 do anything. So we have basically, without the (==)/2 check:
expand_term(X, Y) :- term_expansion(X, H), !, expand_term(H, Y).
expand_term(.. ..) :- /* possibly decend into meta predicate */
But what I would like to see is a kind of a simplification framework added to the expansion framework. So when we decend into a meta predicate and come back, we should call a simplification hook.
It is in accordance with some theories of term rewriting, which say: the normal form (nf) of a compound is a function of the normal form of its parts. The expansion framework would thus not deal with normal forms, only deliver redefinitions of predicates, but the simplification framework would do the normal form work:
nf(f(t_1,..,t_n)) --> f'(nf(t_1),..nf(t_n))
So the simplification hook would take f(nf(t_1), .., nf(t_n)), assuming that expand_term when decending into a meta predicate yields already nf(t_1) .. nf(t_n) for the meta arguments, and then simply give f(nf(t_1), .., nf(t_n)) to the simplifier.
The simplifier would then return f'(nf(t_1), .., nf(t_n)), namely do its work and return a simplified form, based on the assumption that the arguments are already simplified. Such a simplifier can be quite powerful. Jekejeke Prolog delivers such as stage after expansion.
The Jekejeke Prolog simplifier and its integraton into the expansion framework is open source here and here. It is for example used to reorder conjunction, here are the example rules for this purpose:
/* Predefined Simplifications */
sys_goal_simplification(( ( A, B), C), J) :-
sys_simplify_goal(( B, C), H),
sys_simplify_goal(( A, H), J).
Example:
(((a, b), c), d) --> (a, (b, (c, d)))
The Jekejeke Prolog simplifier is extremly efficient, since it can work with the assumption that it receives already normalized terms. It will not unnecessarely repeatedly do pattern matching over the whole given term.
But it needs some rewriting system common practice to write simplfication rules. A simplficiation rule should call simplification when ever it constructs a new term.
In the example above these are the two sys_simplify_goal/2 calls, we do for example not simply return a new term with (B,C) in it, as an expansion rule would do. Since (B,C) was not part of the normalized arguments for sys_goal_simplification/2, we have to normalize it first.
But since the simplifier framework is interwined with the expansion framework, I doubt that it can be called a workflow architecture. There is no specific flow direction, the result is rather a ping pong. Nevertheless the simplfication framework can be used in a modular way.
The Jekejeke Prolog simplifier is also used in the forward chaining clause rewriting. There it does generate from one forward clause multiple delta computation clauses.
Bye

How to avoid using assert and retractall in Prolog to implement global (or state) variables

I often end up writing code in Prolog which involves some arithmetic calculation (or state information important throughout the program), by means of first obtaining the value stored in a predicate, then recalculating the value and finally storing the value using retractall and assert because in Prolog we cannot assign values to variable twice using is (thus making almost every variable that needs modification, global). I have come to know that this is not a good practice in Prolog. In this regard I would like to ask:
Why is it a bad practice in Prolog (though i myself don't like to go through the above mentioned steps just to have have a kind of flexible (modifiable) variable)?
What are some general ways to avoid this practice? Small examples will be greatly appreciated.
P.S. I just started learning Prolog. I do have programming experience in languages like C.
Edited for further clarification
A bad example (in win-prolog) of what I want to say is given below:
:- dynamic(value/1).
:- assert(value(0)).
adds :-
value(X),
NewX is X + 4,
retractall(value(_)),
assert(value(NewX)).
mults :-
value(Y),
NewY is Y * 2,
retractall(value(_)),
assert(value(NewY)).
start :-
retractall(value(_)),
assert(value(3)),
adds,
mults,
value(Q),
write(Q).
Then we can query like:
?- start.
Here, it is very trivial, but in real program and application, the above shown method of global variable becomes unavoidable. Sometimes the list given above like assert(value(0))... grows very long with many more assert predicates for defining more variables. This is done to make communication of the values between different functions possible and to store states of variables during the runtime of program.
Finally, I'd like to know one more thing:
When does the practice mentioned above become unavoidable in spite of various solutions suggested by you to avoid it?
The general way to avoid this is to think in terms of relations between states of your computations: You use one argument to hold the state that is relevant to your program before a calculation, and a second argument that describes the state after some calculation. For example, to describe a sequence of arithmetic operations on a value V0, you can use:
state0_state(V0, V) :-
operation1_result(V0, V1),
operation2_result(V1, V2),
operation3_result(V2, V).
Notice how the state (in your case: the arithmetic value) is threaded through the predicates. The naming convention V0 -> V1 -> ... -> V scales easily to any number of operations and helps to keep in mind that V0 is the initial value, and V is the value after the various operations have been applied. Each predicate that needs to access or modify the state will have an argument that allows you to pass it the state.
A huge advantage of threading the state through like this is that you can easily reason about each operation in isolation: You can test it, debug it, analyze it with other tools etc., without having to set up any implicit global state. As another huge benefit, you can then use your programs in more directions provided you are using sufficiently general predicates. For example, you can ask: Which initial values lead to a given outcome?
?- state0_state(V0, given_outcome).
This is of course not readily possible when using the imperative style. You should therefore use constraints instead of is/2, because is/2 only works in one direction. Constraints are much easier to use and a more general modern alternative to low-level arithmetic.
The dynamic database is also slower than threading states through in variables, because it performs indexing etc. on each assertz/1.
1 - it's bad practice because destroys the declarative model that (pure) Prolog programs exhibit.
Then the programmer must think in procedural terms, and the procedural model of Prolog is rather complicate and difficult to follow.
Specifically, we must be able to decide about the validity of asserted knowledge while the programs backtracks, i.e. follow alternative paths to those already tried, that (maybe) caused the assertions.
2 - We need additional variables to keep the state. A practical, maybe not very intuitive way, is using grammar rules (a DCG) instead of plain predicates. Grammar rules are translated adding two list arguments, normally hidden, and we can use those arguments to pass around the state implicitly, and reference/change it only where needed.
A really interesting introduction is here: DCGs in Prolog by Markus Triska. Look for Implicitly passing states around: you'll find this enlighting small example:
num_leaves(nil), [N1] --> [N0], { N1 is N0 + 1 }.
num_leaves(node(_,Left,Right)) -->
num_leaves(Left),
num_leaves(Right).
More generally, and for further practical examples, see Thinking in States, from the same author.
edit: generally, assert/retract are required only if you need to change the database, or keep track of computation result along backtracking. A simple example from my (very) old Prolog interpreter:
findall_p(X,G,_):-
asserta(found('$mark')),
call(G),
asserta(found(X)),
fail.
findall_p(_,_,N) :-
collect_found([],N),
!.
collect_found(S,L) :-
getnext(X),
!,
collect_found([X|S],L).
collect_found(L,L).
getnext(X) :-
retract(found(X)),
!,
X \= '$mark'.
findall/3 can be seen as the basic all solutions predicate. That code should be the very same from Clockins-Mellish textbook - Programming in Prolog. I used it while testing the 'real' findall/3 I implemented. You can see that it's not 'reentrant', because of the '$mark' aliased.

left_of exercise from The Art Of Prolog

In the book we are asked to define the predicates left_of, right_of, above, and below using the following layout.
% bike camera
% pencil hourglass butterfly fish
left_of(pencil, hourglass).
left_of(hourglass, butterfly).
left_of(butterfly, fish).
above(bike, pencil).
above(camera, butterfly).
right_of(Obj1, Obj2) :-
left_of(Obj2, Obj1).
below(Obj1, Obj2) :-
above(Obj2, Obj1).
This seems to find correct solutions.
Later in the book we are asked to add a recursive rule for left_of. The only solution I could find is to use a different functor name: left_of2. So I've basically reimplemented the ancestor relationship.
left_of2(Obj1, Obj2) :-
left_of(Obj1, Obj2).
left_of2(Obj1, Obj2) :-
left_of(Obj1, X),
left_of2(X, Obj2).
In my attempts to reuse left_of, I can get all the correct solution but on the final redo, a stack overflow occurs. I'm guessing that's because I don't have a correct base case defined. Can this be coded using left_of for facts and a recursive procedure?
As mentioned in the comments, it is an unfortunate fact that in Prolog you must have separately named predicates to do this. If you don't, you'll wind up with something that looks like this:
left_of(X,Z) :- left_of(X,Y), left_of(Y,Z).
which gives you unbounded recursion twice. There's nothing wrong in principle with facts and predicates sharing the same name--in fact, it's pretty common for a base case rule to look like a fact. It's just that handling a transitive closure situation like this results in stack overflows unless one of the two steps is finite, and there's no other way to ensure that in Prolog than by naming them separately.
This is far from the only case in Prolog where you are compelled to break work down into separate predicates. Other commonly-occurring cases include computational loops with initializers or finalizers.
Conventionally one would wind up naming the predicate differently from the fact. For instance, directly_left_of for the facts and left_of for the predicate. Using the module system or Logtalk you can easily hide the "direct" version and encourage your users to use the transitive version. You can also make the intention more explicit without disallowing it by using an uncomfortable name for the hidden one, like left_of_.
In other languages, a function is a more opaque, larger sort of abstraction and there are facilities for hiding considerable work behind one. Prolog's predicates, by comparison, are "simpler," which used to bother me. Nowadays I'm glad that they're simpler because there's enough other stuff going on that I'm glad I don't also have to figure out variable-arity predicates or keyword arguments (though you can easily simulate both with lists, if you need to).

Resources