Does prolog have a spread/splat/*args operator? - prolog

In many procedural languages (such as python), I can "unpack" a list and use it as arguments for a function. For example...
def print_sum(a, b, c):
sum = a + b + c
print("The sum is %d" % sum)
print_sum(*[5, 2, 1])
This code will print: "The sum is 8"
Here is the documentation for this language feature.
Does prolog have a similar feature?
Is there a way to replicate this argument-unpacking behaviour in Prolog?
For example, I'd like to unpack a list variable before passing it into call.
Could I write a predicate like this?
assert_true(Predicate, with_args([Input])) :-
call(Predicate, Input).
% Where `Input` is somehow unpacked before being passed into `call`.
...That I could then query with
?- assert_true(reverse, with_args([ [1, 2, 3], [3, 2, 1] ])).
% Should be true, currently fails.
?- assert_true(succ, with_args([ 2, 3 ]).
% Should be true, currently fails.
?- assert_true(succ, with_args([ 2, 4 ]).
% Should be false, currently fails.
Notes
You may think that this is an XY Problem. It could be, but don't get discouraged. It'd be ideal to receive an answer for just my question title.
You may tell me that I'm approaching the problem poorly. I know your intentions are good, but this kind of advice won't help to answer the question. Please refer to the above point.
Perhaps I'm approaching Prolog in too much of a procedural mindset. If this is the case, then what mindset would help me to solve the problem?
I'm using SWI-Prolog.

The built-in (=..)/2 (univ) serves this purpose. E.g.
?- G =.. [g, 1, 2, 3].
G = g(1,2,3).
?- g(1,2,3) =.. Xs.
Xs = [g,1,2,3].
However, note that many uses of (=..)/2 where the number of arguments is fixed can be replaced by call/2...call/8.

First: it is too easy, using unification and pattern matching, to get the elements of a list or the arguments of any term, if you know its shape. In other words:
sum_of_three(X, Y, Z, Sum) :- Sum is X+Y+Z.
?- List = [5, 2, 1],
List = [X, Y, Z], % or List = [X, Y, Z|_] if the list might be longer
sum_of_three(X, Y, Z, Sum).
For example, if you have command line arguments, and you are interested only in the first two command line arguments, it is easy to get them like this:
current_prolog_flag(argv, [First, Second|_])
Many standard predicates take lists as arguments. For example, any predicate that needs a number of options, as open/3 and open/4. Such a pair could be implemented as follows:
open(SrcDest, Mode, Stream) :-
open(SrcDest, Mode, Stream, []).
open(SrcDest, Mode, Stream, Options) :-
% get the relevant options and open the file
Here getting the relevant options can be done with a library like library(option), which can be used for example like this:
?- option(bar(X), [foo(1), bar(2), baz(3)]).
X = 2.
So this is how you can pass named arguments.
Another thing that was not mentioned in the answer by #false: in Prolog, you can do things like this:
Goal = reverse(X, Y), X = [a,b,c], Y = [c,b,a]
and at some later point:
call(Goal)
or even
Goal
To put it differently, I don't see the point in passing the arguments as a list, instead of just passing the goal as a term. At what point are the arguments a list, and why are they packed into a list?
To put it differently: given how call works, there is usually no need for unpacking a list [X, Y, Z] to a conjunction X, Y, Z that you can then use as an argument list. As in the comment to your question, these are all fine:
call(reverse, [a,b,c], [c,b,a])
and
call(reverse([a,b,c]), [c,b,a])
and
call(reverse([a,b,c], [c,b,a]))
The last one is the same as
Goal = reverse([a,b,c], [c,b,a]), Goal
This is why you can do something like this:
?- maplist(=(X), [Y, Z]).
X = Y, Y = Z.
instead of writing:
?- maplist(=, [X,X], [Y, Z]).
X = Y, Y = Z.

Related

Why does returning false? [duplicate]

I implemented the following power program in Prolog:
puissance(_,0,1).
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
The code does what is supposed to do, but after the right answer it prints "false.". I don't understand why. I am using swi-prolog.
Can do like this instead:
puissance(X,N,P) :-
( N > 0 ->
A is N-1,
puissance(X,A,Z),
P is Z*X
; P = 1 ).
Then it will just print one answer.
(Your code leaves a `choice point' at every recursive call, because you have two disjuncts and no cut. Using if-then-else or a cut somewhere removes those. Then it depends on the interpreter what happens. Sicstus still asks if you want ((to try to find)) more answers.)
Semantic differences
Currently, there are 3 different versions of puissance/3, and I would like to show a significant semantic difference between some of them.
As a test case, I consider the query:
?- puissance(X, Y, Z), false.
What does this query mean? Declaratively, it is clearly equivalent to false. This query is very interesting nevertheless, because it terminates iff puissance/3 terminates universally.
Now, let us try the query on the different variants of the program:
Original definition (from the question):
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Accepted answer:
?- puissance(X, Y, Z), false.
false.
Other answer:
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Obviously, the solution shown in the accepted answer yields a different result, and is worth considering further.
Here is the program again:
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Let us ask something simple first: Which solutions are there at all? This is called the most general query, because its arguments are all fresh variables:
?- puissance(X, Y, Z).
Y = 0,
Z = 1.
The program answers: There is only a single solution: Y=0, Z=1.
That's incorrect (to see this, try the query ?- puissance(0, 1, _) which succeeds, contrary to the same program claiming that Y can only be 0), and a significant difference from the program shown in the question. For comparison, the original program yields:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
ERROR: puissance/3: Arguments are not sufficiently instantiated
That's OK: On backtracking, the program throws an instantiation error to indicate that no further reasoning is possible at this point. Critically though, it does not simply fail!
Improving determinism
So, let us stick to the original program, and consider the query:
?- puissance(1, 1, Z).
Z = 1 ;
false.
We would like to get rid of false, which occurs because the program is not deterministic.
One way to solve this is to use zcompare/3 from library(clpfd). This lets you reify the comparison, and makes the result available for indexing while retaining the predicate's generality.
Here is one possible solution:
puissance(X, N, P) :-
zcompare(C, 0, N),
puissance_(C, X, N, P).
puissance_(=, _, 0, 1).
puissance_(<, X, N, P) :-
A #= N-1,
puissance(X, A, Z),
P #= Z*X.
With this version, we get:
?- puissance(1, 1, Z).
Z = 1.
This is now deterministic, as intended.
Now, let us consider the test case from above with this version:
?- puissance(X, Y, Z), false.
nontermination
Aha! So this query neither throws an instantiation error nor terminates, and is therefore different from all the versions that have hitherto been posted.
Let us consider the most general query with this program:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
X = Z,
Y = 1,
Z in inf..sup ;
Y = 2,
X^2#=Z,
Z in 0..sup ;
Y = 3,
_G3136*X#=Z,
X^2#=_G3136,
_G3136 in 0..sup ;
etc.
Aha! So we get a symbolic representation of all integers that satisfy this relation.
That's pretty cool, and I therefore recommend you use CLP(FD) constraints when reasoning over integers in Prolog. This will make your programs more general and also lets you improve their efficiency more easily.
You can add a cut operator (i.e. !) to your solution, meaning prolog should not attempt to backtrack and find any more solutions after the first successful unification that has reached that point. (i.e. you're pruning the solution tree).
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Layman's Explanation:
The reason prolog attempts to see if there are any more solutions, is this:
At the last call to puissance in your recursion, the first puissance clause succeeds since P=1, and you travel all the way back to the top call to perform unification with P with the eventual value that results from that choice.
However, for that last call to puissance, Prolog didn't have a chance to check whether the second puissance clause would also be satisfiable and potentially lead to a different solution, therefore unless you tell it not to check for further solutions (by using a cut on the first clause after it has been successful), it is obligated to go back to that point, and check the second clause too.
Once it does, it sees that the second clause cannot be satisfied because N = 0, and therefore that particular attempt fails.
So the "false" effectively means that prolog checked for other choice points too and couldn't unify P in any other way that would satisfy them, i.e. there are no more valid unifications for P.
And the fact that you're given the choice to look for other solutions in the first place, exactly means that there are still other routes with potentially satisfiable clauses remaining that have not been explored yet.

Prolog Program Not Merging Sorted Lists Correctly

I have a simple program I'm trying to write in Prolog. Essentially, as I learning exercise, I'm trying to write a program that takes two sorted lists as input, and returns the merged list that is also sorted. I have dubbed the predicate "merge2" as to no be confused with the included predicate "merge" that seems to do this already.
I am using recursion. My implementation is below
merge2([],[],[]).
merge2([X],[],[X]).
merge2([],[Y],[Y]).
merge2([X|List1],[Y|List2],[X|List]):- X =< Y,merge2(List1,[Y|List2],List).
merge2([X|List1],[Y|List2],[Y|List]):- merge2([X|List1],List2,List).
When I run this, I get X = [1,2,4,5,3,6] which is obviously incorrect. I've been able to code multiple times and tried to draw out the recursion. To the best of my knowledge, this should be returning the correct result. I'm not sure why the actualy result is so strange.
Thank you.
QuickCheck is your friend. In this case, the property that you want to verify can be expressed using the following predicate:
sorted(L1, L2) :-
sort(L1, S1),
sort(L2, S2),
merge2(S1, S2, L),
sort(L, S),
L == S.
Note that sort/2 is a standard Prolog built-in predicate. Using the QuickCheck implementation provided by Logtalk's lgtunit tool, which you can run using most Prolog systems, we get:
?- lgtunit::quick_check(sorted(+list(integer),+list(integer))).
* quick check test failure (at test 2 after 0 shrinks):
* sorted([0],[0])
false.
I.e. you code fails for L1 = [0] and L2 = [0]:
?- merge2([0], [0], L).
L = [0, 0] ;
L = [0, 0] ;
false.
Tracing this specific query should allow you to quickly find at least one of the bugs in your merge2/4 predicate definition. In most Prolog systems, you can simply type:
?- trace, merge2([0], [0], L).
If you want to keep duplicates in the merged list, you can use the de facto standard predicates msort/2 in the definition of the property:
sorted(L1, L2) :-
sort(L1, S1),
sort(L2, S2),
merge2(S1, S2, L),
msort(L, S),
L == S.
In this case, running QuickCheck again:
?- lgtunit::quick_check(sorted(+list(integer),+list(integer))).
* quick check test failure (at test 3 after 8 shrinks):
* sorted([],[475,768,402])
false.
This failure is more informative if you compare the query with your clauses that handle the case where the first list is empty...
This is done using difference list and since you are learning it uses reveals, AKA spoiler, which are the empty boxes that you have to mouse over to ravel the contents. Note that the reveals don't allow for nice formatting of code. At the end is the final version of the code with nice formatting but not hidden by a reveal so don't peek at the visible code at the very end if you want to try it for yourself.
This answer takes it that you have read my Difference List wiki.
Your basic idea was sound and the basis for this answer using difference list. So obviously the big change is to just change from closed list to open list.
As your code is recursive, the base case can be used to set up the pattern for the rest of the clauses in the predicate.
Your simplest base case is
merge2([],[],[]).
but a predicate using difference list can use various means to represent a difference list with the use of L-H being very common but not one I chose to use. Instead this answer will follow the pattern in the wiki of using two variables, the first for the open list and the second for the hole at the end of the open list.
Try to create the simple base case on your own.
merge2_prime([],[],Hole,Hole).
Next is needed the two base cases when one of the list is empty.
merge2_prime([X],[],Hole0,Hole) :-
Hole0 = [X|Hole].
merge2_prime([],[Y],Hole0,Hole) :-
Hole0 = [Y|Hole].
Then the cases that select an item from one or the other list.
merge2_prime([X|List1],[Y|List2],Hole0,Hole) :-
X =< Y,
Hole0 = [X|Hole1],
merge2_prime(List1,[Y|List2],Hole1,Hole).
merge2_prime(List1,[Y|List2],Hole0,Hole) :-
Hole0 = [Y|Hole1],
merge2_prime(List1,List2,Hole1,Hole).
Lastly a helper predicate is needed so that the query merge2(L1,L2,L3) can be used.
merge2(L1,L2,L3) :-
merge2_prime(L1,L2,Hole0,Hole),
Hole = [],
L3 = Hole0.
If you run the code as listed it will produce multiple answer because of backtracking. A few cuts will solve the problem.
merge2(L1,L2,L3) :-
merge2_prime(L1,L2,Hole0,Hole),
Hole = [],
L3 = Hole0.
merge2_prime([],[],Hole,Hole) :- !.
merge2_prime([X],[],Hole0,Hole) :-
!,
Hole0 = [X|Hole].
merge2_prime([],[Y],Hole0,Hole) :-
!,
Hole0 = [Y|Hole].
merge2_prime([X|List1],[Y|List2],Hole0,Hole) :-
X =< Y,
!,
Hole0 = [X|Hole1],
merge2_prime(List1,[Y|List2],Hole1,Hole).
merge2_prime(List1,[Y|List2],Hole0,Hole) :-
Hole0 = [Y|Hole1],
merge2_prime(List1,List2,Hole1,Hole).
Example run:
?- merge2([1,3,4],[2,5,6],L).
L = [1, 2, 3, 4, 5, 6].
?- merge2([0],[0],L).
L = [0, 0].
I didn't check this with lots of examples as this was just to demonstrate that an answer can be found using difference list.

Prolog - dividing list into n-elements sections

I have a predict which gets first N elements:
nfirst(N, _, Lnew) :- N =< 0, Lnew = [].
nfirst(_, [], []).
nfirst(N, [X|Y], [X|Y1]) :- N1 is N - 1, nfirst(N1, Y, Y1).
It works:
% nfirst(3,[1,2,3,4,5,6],X).
% X = [1, 2, 3]
I need a predict for divide list like below:
% divide([a,b,c,d,e,f,g,h],[3,2,1,2],X).
% X = [[a,b,c],[d,e],[f],[g,h]]
The best way is using nfirst.
Very similar question to the one I answered here. Again, the trick is to use append/3 plus length/2 to "bite off" a chunk of list, per my comment above:
split_at(N, List, [H|[T]]) :- append(H, T, List), length(H, N).
If you run that, you'll see this:
?- split_at(4, [1,2,3,4,5,6,7,8], X).
X = [[1, 2, 3, 4], [5, 6, 7, 8]] ;
So this is the backbone of your program, and now you just need the usual recursive stuff around it. First, the base case, which says, if I'm out of list, I should be out of split locations, and thus out of result:
divide([], [], []).
Note that explicit base cases like this make your program more correct than something like divide([], _, _) because they will cause you to fail if you get too many split locations for your list size.
Now the recursive case is not difficult, but because split_at/3 puts two things together in a list (probably a bad choice, you could make split_at/4 as an improvement) you have to take them out, and it clouds the logic a bit here while making (IMO) a nicer API on its own.
divide(List, [Split|Splits], [Chunk|Rest]) :-
split_at(Split, List, [Chunk, Remainder]),
divide(Remainder, Splits, Rest).
This should be fairly straightforward: we're just taking a Split location, using it to chop up the List, and repeating the processing on what's left over. It seems to work as you expect:
?- divide([a,b,c,d,e,f,g,h],[3,2,1,2],X).
X = [[a, b, c], [d, e], [f], [g, h]] ;
false.
Hope this helps! Compare to the other answer, it may illuminate things.

Define the predicate Prolog

I'm reviewing some exercise for the coming test and having difficulty at this.
Given a list of integers L, define the predicate: add(L,S) which returns a list of integers S in which each element is the sum of all the elements in L up to the same position.
Example:
?- add([1,2,3,4,5],S).
S = [1,3,6,10,15].
So my question is what define the predicate means? It looks pretty general. I've read some threads but they did not provide much. Thanks!
This is a good exercise to familiarize yourself with two important Prolog concepts:
declarative integer arithmetic to reason about integers in all directions
meta-predicates to shorten your code.
We start with a very simple relation, relating an integer I and a sum of integers S0 to a new sum S:
sum_(I, S0, S) :- S #= S0 + I.
Depending on your Prolog system, you may need a directive like:
:- use_module(library(clpfd)).
to use declarative integer arithmetic.
Second, there is a powerful family of meta-predicates (see meta-predicate) called scanl/N, which are described in Richard O'Keefe's Prolog library proposal, and already implemented in some systems. In our case, we only need scanl/4.
Example query:
?- scanl(sum_, [1,2,3,4,5], 0, Sums).
Sums = [0, 1, 3, 6, 10, 15].
Done!
In fact, more than done, because we can use this in all directions, for example:
?- scanl(sum_, Is, 0, Sums).
Is = [],
Sums = [0] ;
Is = [_2540],
Sums = [0, _2540],
_2540 in inf..sup ;
Is = [_3008, _3014],
Sums = [0, _3008, _3044],
_3008+_3014#=_3044 ;
etc.
This is what we expect from a truly relational solution!
Note also the occurrence of 0 as the first element in the list of partial sums. It satisfies your textual description of the task, but not the example you posted. I leave aligning these as an exercise.
Define the predicate simply means write a predicate that does what the question requires.
In your question you have to write the definition of add/2 predicate( "/2" means that it has two arguments). You could write the definition below:
add(L,S):- add1(L,0,S).
add1([],_,[]).
add1([H|T],Sum,[H1|T1]):- H1 is Sum+H,NSum is Sum+H,add1(T,NSum,T1).
The above predicate gives you the desired output. A simple example:
?- add([1,2,3,4,5],S).
S = [1, 3, 6, 10, 15].
I think the above or something similar predicate is what someone would wait to see in a test.
Some additional information-issues
The problem with the predicate above is that if you query for example:
?- add(S,L).
S = L, L = [] ;
ERROR: is/2: Arguments are not sufficiently instantiated
As you see when you try to ask when your predicate succeeds it gives an obvious solutions and for further solutions it throws an error. This is not a very good-desired property. You could improve that by using module CLPFD:
:- use_module(library(clpfd)).
add(L,S):- add1(L,0,S).
add1([],_,[]).
add1([H|T],Sum,[H1|T1]):- H1 #= Sum+H,NSum #= Sum+H,add1(T,NSum,T1).
Now some querying:
?- add([1,2,3,4,5],S).
S = [1, 3, 6, 10, 15].
?- add(S,[1,3,6]).
S = [1, 2, 3].
?- add(S,L).
S = L, L = [] ;
S = L, L = [_G1007],
_G1007 in inf..sup ;
S = [_G1282, _G1285],
L = [_G1282, _G1297],
_G1282+_G1285#=_G1307,
_G1282+_G1285#=_G1297 ;
...and goes on..
As you can see now the predicate is in the position to give any information you ask! That's because now it has a more relational behavior instead of the functional behavior that it had before due to is/2 predicate. (These are some more information to improve the predicate's behavior. For the test you might not be allowed to use libraries etc... so you may write just a simple solution that at least answers the question).

Prolog dynamic arithmetic expression

I'm new to Prolog and would like to define a simple predicate which calculates the result depending on which function I choose to use in the arithmetic expression.
So, this was my idea:
operation(X,Y, Op, Result):-
Result is X Op Y.
Now, I was expecting this from Prolog:
operation(3,4,'+', X).
X = 7.
But as you can probably guess, Prolog cannot identify Op as an arithmetic operation.
Does anyone have an idea how this is possible?
I could not find anything on the internet yet, even though it is rather basic, I think.
Thanks in advance!
Although the answers by Tudor and gokhans deliver the wanted result, I think there is a more elegant solution.
Portable solution
The following will work in most Prolog implementations:
operation(X, Y, Operator, Result):-
Goal =.. [Operator, X, Y],
Result is Goal.
Extended but SWI-Prolog specific solution
SWI-Prolog allows the definition of custom arithmetic functions. The following code extends the above for use with such user-defined functions coming from other modules:
:- meta_predicate(operation(+,+,2,-)).
operation(X, Y, Module:Operator, Result):-
Goal =.. [Operator, X, Y],
Module:(Result is Goal).
Notice that support for user-defined functions is deprecated in SWI-Prolog and does not work in other Prologs that do not have this feature.
Usage examples
Some examples of using these implementations of operation/4:
?- operation(1, 2, mod, X).
X = 1.
?- operation(1, 2, //, X).
X = 0.
?- operation(1, 2, /, X).
X = 0.5.
?- operation(1, 2, -, X).
X = -1.
?- operation(1, 2, +, X).
X = 3.
You need to tell Prolog if Op is '+' then sum X and Y. You can do that as following
operation(X,Y, Op, Result) :-
Op = '+',
Result is X + Y
;
Op = '-',
Result is X - Y.
You can increase number of operations.

Resources