Prolog: sum the elements of a list - prolog

I am very new to prolog and I'm trying to sum the elements of a list.
So far, I have this:
sum([],_,_). %base case
sum([H|T], Y, _X):-
X2 is H + Y,
sum(T,X2,X2).
testing with sum([1,2,3,4], 0, X) results in an error, but I'm not sure what's wrong with this code. Could someone point me in the right direction?

The code you gave is closer to working than you probably think, but it has a couple problems.
For one, Prolog predicates aren't functions, they don't return results like functions in other languages do. Predicates, instead, declare something about what is true. Later you can give prolog queries and it'll try to make them true.
For example, calls to length/2 are true when the left argument is a list, and the right argument is an int with the length of the list:
?- length([1, 2, 3, 4], 4).
true.
?- length([1, 2, 3, 4], X).
X = 4.
?- length(X, 2).
X = [_2300, _2306].
Looking back at your first line:
sum([],_,_). %base case
This says "sum/3 is always true, as long as the first element is an empty list". You can test this:
?- sum([], -20, hello).
true.
That's probably not what you were intending.
I'm not sure how to put the rest of this without just giving away the answer, but look at what this clause is saying:
sum([H|T], Y, _X):-
X2 is H + Y,
sum(T,X2,X2).
"sum([H|T], Y, WhoCaresIllNeverUseThisVariable) is true if we can recur and prove that sum(T, H+Y, H+Y) is true".
Well, one point, that last argument is a little weird, because in both clauses you assign it to an anonymous variable (_ and _X). What you're saying is, "the third argument never matters and should match literally anything the uses throws at it". I don't think that's what you mean to say.
Second point, I don't know if you realize it but, you're actually computing a sum here! While trying to make sum([1, 2, 3, 4], 0, X) true Prolog will traverse the list and add each element to the middle argument, your accumulator. The summing part works! What you're failing to do is extract the sum from this predicate.
Generally in Prolog you "return" results by making them an additional argument. You could look at length/2 this way. Here's a way you might write it yourself:
my_length([], 0).
my_length([_|Rest], Length) :-
my_length(Rest, Length1),
Length is Length1 + 1.
This function "returns" the length of the array by only being true when the second argument of the predicate is the length of the array.

Related

Prolog tries to find multiple solutions when only one exists

I've made a basic predicate ascending/1 to check if a list is in ascending order, on https://swish.swi-prolog.org.
ascending([]).
ascending([_]).
ascending([X, Y| T]) :-
X =< Y,
ascending([Y|T]).
It shows the following if I query ?- ascending([1, 2, 4, 6]).:
As in, it tries to find more solutions. Pressing Next, 10, 100 or 1,000 just returns false, which is a mystery in and of itself - true and false at the same time? Maybe that's because of the anonymous _? Have I not defined completely enough? Why is it not just returning true?
Most Prolog systems implement first-argument indexing, which allows avoid creating spurious choice-points. Assuming that and a call with the first argument bound, in the case of your code, the Prolog runtime is able to able to distinguish between the first clause, whose first argument is an atom, and the two other clauses, whose first argument are lists. But not able (in general) to distinguish between the second and third clauses and avoid trying both for a goal where the first argument is a list. This results in the creation of a choice-point. Hence the results your get:
?- ascending([1, 2, 4, 6]).
true ;
false.
But we can improve on your solution. For example:
ascending([]).
ascending([Head| Tail]) :-
ascending(Tail, Head).
ascending([], _).
ascending([Head| Tail], Previous) :-
Previous =< Head,
ascending(Tail, Head).
We will now get:
?- ascending([1, 2, 4, 6]).
true.
?- ascending([1, 2, 4, 6, 1]).
false.

Function to find a list in prolog

I am new to Prolog and I am trying to write a function that finds a list that follows some rules.
More specifically, given two numbers, N and K, I want my function to find a list with K powers of two that their sum is N. The list must not contain each power but the total sum of each power. For example if N=13 and K=5, I want my list to be [2,2,1] where the first 2 means two 4, the second 2 means two 2, and the third 1 means one 1 (4+4+2+2+1=13). Consider that beginning from the end of the list each position i represents the 2^i power of 2. So I wrote this code:
sum2(List, SUM, N) :-
List = [] -> N=SUM;
List = [H|T],
length(T, L),
NewSUM is SUM + (H * 2**L),
sum2(T, NewSUM, N).
powers2(N,K,X):-
sum2(X,0,N),
sum_list(X, L),
K = L.
The problem is:
?- sum2([2,2,1],0,13).
true.
?- sum2([2,2,1],0,X).
X = 13.
?- sum2(X,0,13).
false.
?- powers2(X,5,[2,2,1]).
X = 13.
?- powers2(13,5,[2,2,1]).
true.
?- powers2(13,X,[2,2,1]).
X = 5.
?- powers2(13,5,X).
false.
In the cases, X represents the list I expected the output to be a list that follows the rules and not false. Could you help me to find how can I solve this and have a list for output in these cases?
The immediate reason for the failure of your predicate with an unbound list is due to your use of the -> construct for control flow.
Here is a simplified version of what you are trying to do, a small predicate for checking whether a list is empty or not:
empty_or_not(List, Answer) :-
( List = []
-> Answer = empty
; List = [H|T],
Answer = head_tail(H, T) ).
(Side note: The exact layout is a matter of taste, but you should always use parentheses to enclose code if you use the ; operator. I also urge you to never put ; at the end of a line but rather in a position where it really sticks out. Using ; is really an exceptional case in Prolog, and if it's formatted too similarly to ,, it can be hard to see that it's even there, and what parts of the clause it applies to.)
And this seems to work, right?
?- empty_or_not([], Answer).
Answer = empty.
?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).
OK so far, but what if we call this with an unbound list?
?- empty_or_not(List, Answer).
List = [],
Answer = empty.
Suddenly only the empty list is accepted, although we know from above that non-empty lists are fine as well.
This is because -> cuts away any alternatives once it has found that its condition is satisfied. In the last example, List is a variable, so it is unifiable with []. The condition List = [] will succeed (binding List to []), and the alternative List = [H|T] will not be tried. It seems simple, but -> is really an advanced feature of Prolog. It should only be used by more experienced users who know that they really really will not need to explore alternatives.
The usual, and usually correct, way of implementing a disjunction in Prolog is to use separate clauses for the separate cases:
empty_or_not([], empty).
empty_or_not([H|T], head_tail(H, T)).
This now behaves logically:
?- empty_or_not([], Answer).
Answer = empty.
?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).
?- empty_or_not(List, Answer).
List = [],
Answer = empty ;
List = [_2040|_2042],
Answer = head_tail(_2040, _2042).
And accordingly, your definition of sum2 should look more like this:
sum2([], SUM, N) :-
N = SUM.
sum2([H|T], SUM, N) :-
length(T, L),
NewSUM is SUM + (H * 2**L),
sum2(T, NewSUM, N).
This is just a small step, however:
?- sum2(X, 0, 13).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] _2416 is 0+_2428* ...
ERROR: [8] sum2([_2462],0,13) at /home/gergo/sum.pl:5
ERROR: [7] <user>
You are trying to do arithmetic on H, which has no value. If you want to use "plain" Prolog arithmetic, you will need to enumerate appropriate values that H might have before you try to do arithmetic on it. Alternatively, you could use arithmetic constraints. See possible implementations of both at Arithmetics in Prolog, represent a number using powers of 2.

Prolog: Say how Prolog responds to the inquiry and draw a search tree for it ?- member(2, [2, a, X])

How will Prolog respond to the following inquiry? Draw a search tree for the inquiry, too.
?- member(2, [2, a, X]).
So first of all, what does this inquiry mean?
Let's take another more clear example:
?- member(vincent,[yolanda,trudy,vincent,jules]).
Prolog will check if vincent is in the list. It checks one by one, so it will first compare vincent and yolanda. No match, now recursive rule aka go to second clause. Now it looks like that:
?- member(vincent,[trudy,vincent,jules]).
vincent and trudy, no match. Recursive rule:
?- member(vincent,[vincent,jules]).
vincent and vincent, match! So return true.
Back to our example. Prolog will immediately return true as 2 is in the list (namely the head of it).
But how will the search tree look like? I really have no idea and I'm scared they will ask me to draw a search tree in the test...
That query means
For which X is 2 an element of the list [2, a, X]?
Well, let's see how Prolog answers this:
?- member(2, [2, a, X]).
true
; X = 2.
The first answer we get is true which is the empty answer substitution. It means here that 2 is a member of that list for any X. Really any! Can this be true?
?- X = any, member(2, [2, a, X]).
X = any
; false. % that is no solution
It's even true for any!
Now back to the original query: The second answer is a simple solution X = 2. So Prolog tells us that also 2 might be such an element. Alas, we already know that, for we know that this holds for any term. And thus also 2. Therefore, the second answer is redundant.
You can avoid many such redundancies by using memberd/2 instead!
As for the search tree, member/2 always visits the entire list. One solution after the other. So the search tree only depends on the number of elements in the list.

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

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.

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).

Resources