Passing results in prolog - prolog

I'm trying to make a function that has a list of lists, it multiplies the sum of the inner list with the outer list.
So far i can sum a list, i've made a function sumlist([1..n],X) that will return X = (result). But i cannot get another function to usefully work with that function, i've tried both is and = to no avail.

Is this what you mean?
prodsumlist([], 1).
prodsumlist([Head | Tail], Result) :-
sumlist(Head, Sum_Of_Head),
prodsumlist(Tail, ProdSum_Of_Tail),
Result is Sum_Of_Head * ProdSum_Of_Tail.
where sumlist/2 is a SWI-Prolog built-in.
Usage example:
?- prodsumlist([[1, 2], [3], [-4]], Result).
Result = -36.

The part "it multiplies the sum of the inner list with the outer list" isn't really clear, but I believe you mean that, given a list [L1,...,Ln] of lists of numbers, you want to calculate S1*..*Sn where Si is the sum of the elements in Li (for each i).
I assume the existence of plus and mult with their obvious meaning (e.g. plus(N,M,R) holds precisely when R is equal to N+M). First we need predicate sum such that sum(L,S) holds if, and only if, S is the sum of the elements of L. If L is empty, S obviously must be 0:
sum([],0).
If L is not empty but of the form [N|L2], then we have that S must be N plus the sum S2 of the elements in L2. In other words, we must have both sum(L2,S2) (to get S2 to be the sum of the elements of L2) and plus(N,S2,S). That is:
sum([N|L2],S) :- sum(L2,S2), plus(N,S2,S).
In the same way you can figure out the predicate p you are looking for. We want that p(L,R) holds if, and only if, R is the product of S1 through Sn where L=[L1,...,Ln] and sum(Li,Si) for all i. If L is empty, R must be 1:
p([],1).
If L is not empty but of the form [LL|L2], then we have that R must be the product of 'S', the sum of the elements of LL, and 'P', the product of the sums of the lists in L2. For S we have already have sum(LL,S), so this gives us the following.
p([LL|L2],R) :- sum(LL,S), p(L2,P), mult(S,P,R).
One thing I would like to add is that it is probably not such a good idea to see these predicates as functions you might be used to from imperative or functional programming. It is not the case that sumlist([1,..,n],X) returns X = (result); (result) is a value for X such that sumlist([1,...,n],X) is true. This requires a somewhat different mindset. Instead of thinking "How can I calculate X such that p(X) holds?" you must think "When does P(X) hold?" and use the answer ("Well, if q(X) or r(X)!") to make the clauses (p(X) :- q(X) and p(X) :- r(X)).

Here is a rewrite of Kaarel's answer (that's the intention anyway!) but tail-recursive.
prodsumlist(List, Result) :-
xprodsumlist(List,1,Result).
xprodsumlist([],R,R).
xprodsumlist([Head|Rest],Sofar,Result) :-
sumlist(Head, Sum_Of_Head),
NewSofar is Sofar * Sum_Of_Head,
xprodsumlist(Rest, NewSofar, Result).

Related

Write a Prolog query with arity 2 to return the first n numbers of a Lucas sequence in a list

It needs to return a list of all the Lucas numbers up to the one given, I just have to fill in these two blanks for it to work but I can't seem to figure that out
lucas(0, []):-!.
lucas(1, [2]):-!.
lucas(2, [2, 1]):-!.
lucas(N,L) :-
Y is N-1,
lucas(Y, X),
append(_, [A,B], X),
C is completeHere,
append(completeHere).
That first use of append will get the last two things in a list into A and B:
?- append(_, [A,B], [cow,dog,cat,sheep,fox]).
A = sheep,
B = fox
Wikipedia says:
The Lucas series has the same recursive relationship as the Fibonacci sequence, where each term is the sum of the two previous terms,
so there lucas(Y, X) an (annoyingly named) variable X has the previous terms, and A, B now have the two previous terms, so you can calculate C is ... using those.
Then you need to append the new calculated C (as a list [C]) onto the previous terms, to get the new L.

How can I verify if a coordinate is in a list

I'm generating random coordinates and adding on my list, but first I need verify if that coordinate already exists. I'm trying to use member but when I was debugging I saw that isn't working:
My code is basically this:
% L is a list and Q is a count that define the number of coordinate
% X and Y are the coordinate members
% check if the coordniate already exists
% if exists, R is 0 and if not, R is 1
createCoordinates(L,Q) :-
random(1,10,X),
random(1,10,Y),
convertNumber(X,Z),
checkCoordinate([Z,Y],L,R),
(R is 0 -> print('member'), createCoordinates(L,Q); print('not member'),createCoordinates(L,Q-1).
checkCoordinate(C,L,R) :-
(member(C,L) -> R is 0; R is 1).
% transforms the number N in a letter L
convertNumber(N,L) :-
N is 1, L = 'A';
N is 2, L = 'B';
...
N is 10, L = 'J'.
%call createCoordinates
createCoordinates(L,20).
When I was debugging this was the output:
In this picture I'm in the firts interation and L is empty, so R should be 1 but always is 0, the coordinate always is part of the list.
I have the impression that the member clause is adding the coordinate at my list and does'nt make sense
First off, I would recommend breaking your problem down into smaller pieces. You should have a procedure for making a random coordinate:
random_coordinate([X,Y]) :-
random(1, 10, XN), convertNumber(XN, X),
random(1, 10, Y).
Second, your checkCoordinate/3 is converting Prolog's success/failure into an integer, which is just busy work for Prolog and not really improving life for you. memberchk/2 is completely sufficient to your task (member/2 would work too but is more powerful than necessary). The real problem here is not that member/2 didn't work, it's that you are trying to build up this list parameter on the way out, but you need it to exist on the way in to examine it.
We usually solve this kind of problem in Prolog by adding a third parameter and prepending values to the list on the way through. The base case then equates that list with the outbound list and we protect the whole thing with a lower-arity procedure. In other words, we do this:
random_coordinates(N, Coordinates) :- random_coordinates(N, [], Coordinates).
random_coordinates(0, Result, Result).
random_coordinates(N, CoordinatesSoFar, FinalResult) :- ...
Now that we have two things, memberchk/2 should work the way we need it to:
random_coordinates(N, CoordinatesSoFar, FinalResult) :-
N > 0, succ(N0, N), % count down, will need for recursive call
random_coordinate(Coord),
(memberchk(Coord, CoordinatesSoFar) ->
random_coordinates(N, CoordinatesSoFar, FinalResult)
;
random_coordinates(N0, [Coord|CoordinatesSoFar], FinalResult)
).
And this seems to do what we want:
?- random_coordinates(10, L), write(L), nl.
[[G,7],[G,3],[H,9],[H,8],[A,4],[G,1],[I,9],[H,6],[E,5],[G,8]]
?- random_coordinates(10, L), write(L), nl.
[[F,1],[I,8],[H,4],[I,1],[D,3],[I,6],[E,9],[D,1],[C,5],[F,8]]
Finally, I note you continue to use this syntax: N is 1, .... I caution you that this looks like an error to me because there is no distinction between this and N = 1, and your predicate could be stated somewhat tiresomely just with this:
convertNumber(1, 'A').
convertNumber(2, 'B').
...
My inclination would be to do it computationally with char_code/2 but this construction is actually probably better.
Another hint that you are doing something wrong is that the parameter L to createCoordinates/2 gets passed along in all cases and is not examined in any of them. In Prolog, we often have variables that appear to just be passed around meaninglessly, but they usually change positions or are used multiple times, as in random_coordinates(0, Result, Result); while nothing appears to be happening there, what's actually happening is plumbing: the built-up parameter becomes the result value. Nothing interesting is happening to the variable directly there, but it is being plumbed around. But nothing is happening at all to L in your code, except it is supposedly being checked for a new coordinate. But you're never actually appending anything to it, so there's no reason to expect that anything would wind up in L.
Edit Notice that #lambda.xy.x solves the problem in their answer by prepending the new coordinate in the head of the clause and examining the list only after the recursive call in the body, obviating the need for the second list parameter.
Edit 2 Also take a look at #lambda.xy.x's other solution as it has better time complexity as N approaches 100.
Since i had already written it, here is an alternative solution: The building block is gen_coord_notin/2 which guarantees a fresh solution C with regard to an exclusion list Excl.
gen_coord_notin(C, Excl) :-
random(1,10,X),
random(1,10,Y),
( memberchk(X-Y, Excl) ->
gen_coord_notin(C, Excl)
;
C = X-Y
).
The trick is that we only unify C with the new result, if it is fresh.
Then we only have to fold the generations into N iterations:
gen_coords([], 0).
gen_coords([X|Xs], N) :-
N > 0,
M is N - 1,
gen_coords(Xs, M),
gen_coord_notin(X, Xs).
Remark 1: since coordinates are always 2-tuples, a list representation invites unwanted errors (e.g. writing [X|Y] instead of [X,Y]). Traditionally, an infix operator like - is used to seperate tuples, but it's not any different than using coord(X,Y).
Remark 2: this predicate is inherently non-logical (i.e. calling gen_coords(X, 20) twice will result in different substitutions for X). You might use the meta-level predicates var/1, nonvar/1, ground/1, integer, etc. to guard against non-sensical calls like gen_coord(1-2, [1-1]).
Remark 3: it is also important that the conditional does not have multiple solutions (compare member(X,[A,B]) and memberchk(X,[A,B])). In general, this can be achieved by calling once/1 but there is a specialized predicate memberchk/2 which I used here.
I just realized that the performance of my other solutions is very bad for N close to 100. The reason is that with diminishing possible coordinates, the generate and test approach will take longer and longer. There's an alternative solution which generates all coordinates and picks N random ones:
all_pairs(Ls) :-
findall(X-Y, (between(1,10,X), between(1,10,Y)), Ls).
remove_index(X,[X|Xs],Xs,0).
remove_index(I,[X|Xs],[X|Rest],N) :-
N > 0,
M is N - 1,
remove_index(I,Xs,Rest,M).
n_from_pool(_Pool, [], 0).
n_from_pool(Pool, [C|Cs], N) :-
N > 0,
M is N - 1,
length(Pool, L),
random(0,L,R),
remove_index(C,Pool,NPool,R),
n_from_pool(NPool, Cs, M).
gen_coords2(Xs, N) :-
all_pairs(Pool),
n_from_pool(Pool, Xs, N).
Now the query
?- gen_coords2(Xs, 100).
Xs = [4-6, 5-6, 5-8, 9-6, 3-1, 1-3, 9-4, 6-1, ... - ...|...] ;
false.
succeeds as expected. The error message
?- gen_coords2(Xs, 101).
ERROR: random/1: Domain error: not_less_than_one' expected, found0'
when we try to generate more distinct elements than possible is not nice, but better than non-termination.

Prolog - return second to last list element

puzzling over a problem of trying to return the second to last element in a list written in Prolog. This language is interesting to use but I'm having trouble getting my head wrapped around it. Here is what I have:
secondLast([X], X).
secondLast(X, [Y], X) :- secondLast(Y, K).
secondLast(X, [Y|Z], K) :- secondLast(Y, Z, K).
secondLast([X|Z], Ans) :- secondLast(X, Z, Ans).
so calling secondLast([a, b, c, d], X).
X should equal c.
Any ideas?
Thanks!
you should apply pattern matching:
secondLast([X,_], X).
secondLast([_|T], X) :- secondLast(T, X).
Can be just:
secondLast(L, X) :-
append(_, [X, _], L).
Sergey and CapelliC have offered two nice solutions to the problem. Let's have a look to see what's wrong with the original:
1) secondLast([X], X).
2) secondLast(X, [Y], X) :- secondLast(Y, K).
3) secondLast(X, [Y|Z], K) :- secondLast(Y, Z, K).
4) secondLast([X|Z], Ans) :- secondLast(X, Z, Ans).
In Prolog, since it is about defining relations between entities with predicates, not defining functions, it helps to describe what a predicate means in terms of, "Something is true if some other things are true". The if in Prolog is expressed as :-.
We'll look at clause #4 since this appears to be your main clause. This one says, Ans is the second to last element of [X|Z] if Ans is the second to last element of Z with X as the head. It's unclear what this 3-argument version of secondLast means. However, if the list is 3 or more elements, it seems clear that X will become irrelevant (as will be seen in clauses 2 and 3).
Clause #1 says, X is the second to last element in list [X]. However, the element X is the last and only element in the list [X]. So this clause is logically incorrect.
Clauses #2 is a bit confusing. It introduces a variable in the clause, K, which is only used once and not defined or used anywhere else in the clause. It also ignores X because, as described above, it has become irrelevant since it's no longer a candidate for second-to-last element. Prolog has given you a warning about singleton elements K and X, which is similar to the warning in C that a variable is "defined but never used" or "is assigned a value that is never used". Clause #3 has the same issue.
In all that, I think I can see what you were trying to do, which is to say that, Ans is second to last element of [X|Z] if there's one more element after X, which would be true, but would be limited to being correct if the list [X|Z] is a 2-element list. In other words, your main clause almost assumes that the answer is ultimately X. If it isn't, it attempts to introduce a new candidate, Y in clauses 2 and 3, but this candidate has no way to "make it back" to the original, main clause.
I'll go back now to CapelliC's solution and describe how one comes to it:
1) secondLast([X,_], X).
2) secondLast([_|T], X) :- secondLast(T, X).
The first clause says, X is the second to last element in the 2-element list, [X,_] which is true. And we don't care what the last element is so we just call it, _. We could have called it Y ([X,Y]), but then Prolog would warn about a singleton variable since we don't need or use Y.
The second clause says, X is the second to last element of list [_|T] if X is the second to last element of the tail, T. This is also true of any list that is 3 or more elements. That's fine since the base case, clause one, takes care of the 2-element list. Clause two will, recursively, reduce down to clause one and finally succeed with the right answer. In this second clause, if X is taken from T, then we don't care what the head of the list is since it has become irrelevant, so we use _ as the head in this case (this corresponds to the X in your original clause #4).
In Sergey's answer:
secondLast(L, X) :-
append(_, [X, _], L).
This says, X is second to last element in list L if L is a two element list with X as the first element ([X,_]) appended to the end of some other list (_). Note again that we're using _ for the variables which will have values but we don't care what those values are in this case. So, for example: 2 is the second to last element of [1,2,3] if [1,2,3] is [2,_] appended to some other list and it is: if you append [2,3] to [1] you get [1,2,3].

Understanding difference lists (Prolog)

I'm having trouble understanding difference list, particularly in this predicate:
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
palindrome(A, B),
B=[C|D].
Could anyone help me follow what's happening?
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
palindrome(A, B),
B=[C|D].
Seeing the arguments to this predicate as a difference list, the first clause says, a list from A to A (i.e., an empty list) is a palindrome.
The second clause says, a one-element list is a palindrome, whatever that one element is.
Don't panic! Difference lists are just lists with explicit end "pointer"
A normal list, say [1,2,3], is a difference between its start and its end; the end of a normal list is always an empty list, []. That is to say, for a list [1,2,3] we are supposed to call this predicate as palindrome( [1,2,3], []) — namely, check whether the difference list [1,2,3] - [] is a palindrome.
From the operational point of view, a difference list is nothing but a (possibly open-ended) list with explicitly maintained "end pointer", for example: A - Z where A = [1,2,3|Z] and Z = []. Indeed, [1,2,3|[]] is the same as [1,2,3]. But when Z is not instantiated yet, the list A is still open ended - its "end pointer" Z can be instantiated to anything (but only once, of course, sans the backtracking).
If we were to instantiate Z later to an open-ended list, say, Z = [4|W], we'd get a new, extended difference list A - W where A = [1,2,3,4|W]. The old one would become A - Z = [1,2,3,4|W] - [4|W], i.e. still representing a prefix [1,2,3] of an open-ended list [1,2,3,4 ...]. Once closed, e.g. with W = [5], all the pairs of logvars still represent their corresponding difference lists (i.e. A - Z, A - W ...), but A is not open-ended anymore, so can't be extended anymore.
Instead of using the - functor, it is customary to just use both parts of the diff list definition as separate arguments to a predicate. When we always use / treat them as if they were two parts of a pair, then they form a pair, conceptually. It's the same thing.
Continuing. The third clause says, for [C|A]-D to be a palindrome, A-B must be a palindrome, and B must be [C|D]. A, D, B are lists, C is an element of a list. This might be confusing; let's use V instead. Also, use Z and Y instead of D and B, to remind us of "the end" of a list:
palindrome([V|A], Z):- palindrome(A, Y), Y=[V|Z].
V ................. V ----
^ ^ ^
| | |
| | Z
A Y = [V|Z]
Indeed, when the ...... core is a palindrome, putting two Vs around it gives us another palindrome.
The following is a summary that hopefully distills the best of the previous discussion, and adds one small but significant simplification.
First, the original question should be understood in the context of the problem at hand, which can be formulated as defining a Prolog predicate which will check whether a list is a palindrome, or more generally to generate palindromes. We wish to explore an implementation using difference lists, so we can begin as follows:
% List is a palindrome if List - [] is a palindrome:
palindrome( List ) :- palindrome(List, []).
(As explained elsewhere, if a list, List, is the concatenation of two lists
Front and Back, then Front can be viewed as being the difference
between List and Back, that is, Front can be regarded as equivalent to (List - Back).)
To define palindrome/2, we begin with the two "base cases", an empty list and a singleton:
% The empty list (L-L) is a palindrome:
palindrome(L, L).
% A singleton list, ([X|L] - L), is a palindrome:
palindrome([X|L], L).
Let us now turn to the general case.
If a list with more than one element is to be a palindrome, then it
will look like this: E ... E
where ... is a (possibly empty) palindrome.
Tacking on a tail, Tail, our list must look like: E ... E Tail
Writing this regular list as [E|Rest], we can now see that the original list ( [E|Rest] - Tail ) is a palindrome if (Rest - [E|Tail]) is a palindrome,
or in terms of our predicate palindrome/2:
palindrome( [E|Xs], Tail ) :- palindrome(Xs, [E|Tail]).
It's easy to see that this is equivalent to the original formulation.
That's it! Now we can, for example, generate templates for palindromes:
?- palindrome( X ).
X = [] ;
X = [_G1247] ;
X = [_G1247, _G1247] ;
X = [_G1247, _G1253, _G1247] ;
X = [_G1247, _G1253, _G1253, _G1247]
....

Sum of a list in prolog

I'm reading 'the art of prolog' book and I found an exercise that reads 'Define the relation sum(ListOfIntegers,Sum) which holds if Sum is the sum of the ListOfIntegers, without using any auxiliary predicate' .I came up with this solution:
sum([],Sum).
sum([0|Xs], Sum):-sum(Xs, Sum).
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Which does not work exactly as I would want it to.
?- sum([s(s(0)),s(0),s(s(s(0)))],X).
true ;
false.
I was expecting X to be
s(s(s(s(s(s(0))))))
I thought that the problem is that I have to 'initialize' Sum to 0 in the first 'iteration' but that would be very procedural and unfortunately I'm not quite apt in prolog to make that work.
Any ideas or suggestions?
Your first clause should read
sum([], 0).
With that change, the vacuous true return goes away and you're left with one problem: the third clause reverses the logic of summation. It should be
sum([s(X)|Xs], s(Sum)) :- sum([X|Xs], Sum).
because the number of s/1 terms in the left argument to sum/2 should be equal to the number of them in the right argument.
The best way to localize the problem is to first simplify your query:
?- sum([0],S).
true.
?- sum([],S).
true.
Even for those, you get as an answer that any S will do. Like
?- sum([],s(s(0))).
true.
Since [] can only be handled by your fact, an error must lie in that very fact.
You stated:
sum([], Sum).
Which means that the sum of [] is just anything. You probably meant 0.
Another error hides in the last rule... After fixing the first error, we get
?- sum([0],Sum).
Sum = 0.
?- sum([s(0)],Sum).
false.
Here, the last clause is responsible. It reads:
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Recursive rules are relatively tricky to read in Prolog. The simplest way to understand them is to look at the :- and realize that this should be an arrow ← (thus a right-to-left arrow) meaning:
provided, that the goals on the right-hand side are truewe conclude what is found on the left-hand side
So, compared to informal writing, the arrows points into the opposite direction!
For our query, we can consider the following instantiation substituting Xs with [] and X with 0.
sum([s(0)| [] ], Sum) :- sum([0| []],s(Sum)).
So this rule now reads right-to-left: Provided, sum([0],s(Sum)) is true, ... However, we do know that only sum([0],0) holds, but not that goal. Therefore, this rule never applies! What you intended was rather the opposite:
sum([s(X)|Xs], s(Sum)):-sum([X|Xs],Sum).
I'm not really following your logic, what with all the seemingle extraneous s(X) structures floating about.
Wouldn't it be easier and simpler to do something like this?
First, define your solution in plain english, thus:
The sum of an empty list is 0.
The sum of a non-empty list is obtained by adding the head of the list to the sum of the tail of the list.
From that definition, the prolog follows directly:
sum( [] , 0 ) . % the sum of an empty list is 0.
sum( [X|Xs] , T ) :- % the sum of an non-empty list is obtained by:
sum( Xs , T1 ) , % - first computing the sum of the tail
T is X + T1 % - and then, adding that the to head of the list
. % Easy!

Resources