Prolog evaluating how two lists compare to eachother - list

Note: Near complete beginner to logic programming
I need to compare two lists of integers and figure out if one is greater, greater-equal, or they are both equal.
For example:
compare_list([1, 2, 3], [1, 2, 4], C).
C = greater,
C = greater-equal.
compare_list([1, 2, 3], [1, 2, 4], C).
C = equal.
So far the closest I have been able to get has been...
compare_list([],[],_).
compare_list([X|XS],[Y|YS],C):-
X > Y,
compare_list(XS,YS,C),
C = 'greater'.
compare_list([X|XS],[Y|YS],C):-
X >= Y,
compare_list(XS,YS,C),
C = 'greater-equal'.
compare_list([X|XS],[Y|YS],C):-
X == Y,
compare_list(XS,YS,C),
C = 'equal'.
Now that obviously doesn't work as needed because it is always comparing the first element of each list and seeing if the C value holds for all of the values. However I cannot think of a way to make it work as intended.
Edit:
The earlier a value is in a list, the more important it is. So [2,2] > [1,3] > [1,2]
Tips would be appreciated. Thanks.
Edit:
Solved by waiting until the end to assign C to anything.

In your solution you use (>)/2, (>=)/2 and (==)/2. The first two will evaluate their arguments as arithmetic expressions prior to a comparison. And (==)/2 will compare due to term order. You will have to decide for one of them or another term order. But you cannot mix them.
The second remark is that you would also need something as 'less' as a result.
If two elements already compare as (<)/2, there is no need for further comparison.
Also, equality can only be stated in the fact, but not before.
Consider to use the built-in predicate `compare/3`:
?- compare(R, [1, 2, 3], [1, 2, 4]).
R = (<).
?- compare(R, [1, 2, 3], [1, 2, 3]).
R = (=).
Should you write your own comparison predicate, better use the very same argument order and the same terms as result. That is, <, =, and >. It does not make a lot of sense, to expect >= to be a result. After all, two identical lists would then have three different solutions =<, =, >=.
From your description, it is not clear to me what you expect, if both lists are of different length.

According to your definition of "greater" there is no need to continue the recursion after you find that X>Y. If you reach the end of the recursion (as chac said) you'll know that the two lists are equal.
To get "greater-equal" you should instead check that X is not less than Y. You may think of this as "if X is less than Y than fail". Take a look at negation as failure.

You can stop comparing at the first ineguagliance. If you reach the end of (both) lists, that means lists are equals.

The following code will check whether two list are equal or not
is_equal([],[]).
is_equal([H1|T1],[H2|T2]):- H1=:=H2,is_equal(T1,T2).

Related

Comparing list elements to a predicate

I need to construct a a predicate compare_to_predicate/3. It takes in a given predicate and list of numbers and proceeds to compare every element in the list using that predicate.
The given predicates are
- is_odd
- is_even
- greater_than(X)
For example:
?- compare_to_predicate([8,13,1,500], [is_odd], X).
X = [13, 1].
?- compare_to_predicate([8,13,1,500], [greater_than, 10], X).
X = [13, 500].
What I have come up with thus far is:
is_odd(X):- 1 is mod(X,2).
is_even(X):- 0 is mod(X,2).
greater_than(X,Y):- X<Y.
compare_to_predicate([],_,[]).
compare_to_predicate([H|Tail],Functor,[H|X]):- Term =.. [Functor,H], Term, compare_to_predicate(Tail,Functor,X).
I have a number of issues:
1)
?- compare_to_predicate([2,10,8,300],is_even,X).
will produce
X = [2, 10, 8, 300].
but
compare_to_predicate([2,10,8,301],is_even,X).
will produce
false.
I assume it has to do with the predicate encountering a number that will not return true on is_even and then terminating the whole compare_to_predicate with a false. In that case is the solution to somehow make it ignore odd numbers instead of evaluating them? If so, how would I do that?
2)
It seems that the given predicate I pass into compare_to_predicate has to have the type List as seen in
?- compare_to_predicate([8,13,1,500], [is_odd], X).
and
?- compare_to_predicate([8,13,1,500], [greater_than, 10], X).
I am currently simply passing a normal predicate into the Term. I'm not quite sure on how I'm supposed to do that.
It seems that compare_to_predicate([H|Tail],[Functor],[H|X]):- Term =.. [Functor,H], Term, compare_to_predicate(Tail,[Functor],X)
did the trick here. Finally:
3)
?- compare_to_predicate([8,13,1,500], [greater_than, 10], X).
It seems I need to make compare_to_predicate able to take in predicates with different arity as shown here. Is the solution supposed to be something like this?
(Term =.. [Functor,A]; Term=.. [Functor,A,B]).
Any help will be appreciated.
You kind of need to decide what compare_to_predicate/3 is supposed to do with values that fail the goal. I see basically three ways this can go:
It can behave as a filter, and the third argument is unified with the values in the first argument that pass.
It can behave as a for-all, and the third argument is unified with the whole list if they all pass and fails otherwise (your current behavior)
It can behave like an for-each that just applies the predicate to each item in the list and discards the result. There is no meaningful value for the third parameter in this case.
By the way, the term surgery you're doing with =../2 is not necessary; call/N will do the right thing if you do something like call(greater(10), 20), so you can just allow the user to call your predicate like this: compare_to_predicate([1,2,3,4], greater(2), X) and use call to build the goal.
Doing the first one is pretty straightforward:
filter([], _, []).
filter([X|Xs], P, Result) :-
filter(Xs, P, Xs1),
(call(P, X) -> Result = [X|Xs1] ; Result = Xs1).
Doing the second one is also pretty straightforward:
forall([], _, []).
forall([X|Xs], P, [X|Xs]) :- call(P, X), forall(Xs, P, Xs).
Doing the third one is not terribly hard:
foreach([], _).
foreach([X|Xs], G) :- once(call(G, X) ; true), foreach(Xs, G).

Turn a tuple into a list

I've searched and strangely didn't find much on this . How can I turn a tuple of unknown length into a list in prolog?
For example:
List=[1,2,3,4], Tuple=(1,2,3,4).
When you are stuck with term conversion, it is often a good idea to get an understanding of what a term actually denotes.
You can use write_canonical/1 to get the canonical form of a term.
In your case:
?- Tuple = (1,2,3,4), write_canonical(Tuple).
','(1,','(2,','(3,4)))
Tuple = (1, 2, 3, 4).
This makes it clear that we are actually talking about compound terms of the form (A,B)—written in prefix notation as ','(A,B)—whose arguments are either integers or again such compound terms. Such terms are also called "and lists" in Prolog, and Prolog goals also have such a shape. Note in particular that these are not really "tuples", certainly not in a "first class citizen" sense, only compound terms much like any other compound terms.
Thus, we only need to reason about these 2 possible cases:
integer
term of the form (A,B).
Further, when describing lists, always consider using dcg notation for convenience.
For example:
tuple_list(I) --> { integer(I) }, [I].
tuple_list((A,B)) --> tuple_list(A), tuple_list(B).
Now we have:
?- Tuple = (1,2,3,4), phrase(tuple_list(Tuple), Ls).
Tuple = (1, 2, 3, 4),
Ls = [1, 2, 3, 4].
This solves your task of converting from such terms to lists.
However, the most general query yields no answers:
?- phrase(tuple_list(Tuple), Ls).
ERROR: Out of local stack
I leave generalizing tuples_list//1 so that it works in all directions as an exercise.
You have got two useful answers already. As mentioned, you generally don't use a "tuple" in the notation (1, 2, 3, 4): this is not a flat data structure as in say Haskell, it is a nested data structure. The Prolog way would be to use a term with arity 4, for example, quadruple(1, 2, 3, 4). The name of course doesn't matter, but usually, you use a descriptive name of some sort.
Then, to convert the arguments of a term to a list, you use the "univ" operator =.. like this:
Term =.. [Name|Arguments]
so:
?- foo(1, 2, 3, 4) =.. [foo|Args].
Args = [1, 2, 3, 4].
In the special case of tuples with two elements (pairs), the functor -/2 is commonly used. The dash is also an infix operator, so you can write 1-a instead of -(1, a). Quite a few library predicates that work on pairs expect them as -/2, for example:
?- keysort([1-c, 2-a, -(0, b), 1-a], S).
S = [0-b, 1-c, 1-a, 2-a].
tuples in Prolog are rarely used, but a quick conversion could be
list_tuple([A,B|L], (A,R)) :- list_tuple([B|L], R).
list_tuple([A,B], (A,B)). % I don't think unary tuples make sense...
?- list_tuple([1,2,3,4],T).
T = (1, 2, 3, 4) ;
false.
this doesn't work very well on 'backward mode'
?- list_tuple(L,(1,2,3,4)).
L = [1, 2, 3, 4] ;
L = [1, 2, (3, 4)] ....
you can try to place a cut to get it deterministic, I've provided clauses in order as required...
Using SWI-Prolog, "tuples" and lists can be converted using the built-in library predicate comma_list/2.
comma_list(C, [1, 2, 3]).
% C = (1, 2, 3).
comma_list((1, 2, 3), L).
% L = [1, 2, 3].
comma_list((a, foo(bar), C), [a, B, c]).
% C = c,
% B = foo(bar).
See the documentation for more usage examples.
It can be a bit tricky to search for because the documentation doesn't necessarily refer to terms like (1, 2, 3) as a "tuple", but it describes them as a "nested term over the ,/2 functor". Also provided is semicolon_list/2 which will perform the same operations with the ;/2 functor instead.

Postfix expression list evaluation

I have written a program to evaluate a post-fix expression in prolog recursively from an expression list. For example, given the following list:
[+,1,2]
It should return 3. They way I have constructed my predicate is to call itself recursively until it reaches the end of the list so that it reads values backwards. (the same as reading this list from left to right:[2,1,+]).
My problem is that when I try to return more than one value through the recursive calls all the values suddenly disappear.
Here's the code:
eval_list([Head|Tail],_,Result):-
Tail==[], % last element of list
Result=Head,
write(Head),
write(' was stored in Result!\n').
eval_list([Head|Tail],Store1,Result):-
eval_list(Tail,Store2, NewResult),
(\+integer(Store2))
->
% if no integer is bound to Store2, bind Store1 to Head
Store1=Head,
Result is NewResult,
write(Head),
write(' is stored value!\n')
; (integer(Store2)) ->
% if an integer is bound to store2, we perform operation specified by the Head with the stored number
X is Store2+NewResult,
Result is X,
write('performed operation!\n')
;
% if doesnt catch either of these states the program is broken
( print('something broke\n'),
print(Store1),
nl,
print(Store2),
nl,
print(Head),
nl,
print(Result),
nl
).
I get the following output:
?- eval_list([+,1,2],X,Result).
2 was stored in Result!
1 is stored value!
something broke
_G1162
_L147
+
_G1163
true.
I don't understand why my values disappear, or if there is a better way to evaluate the list.
Some advice on your programming technique. You should use head matching and unification instead of explicit unification in the body of your predicate definitions, and if-else constructs. You should also avoid not tail-recursive recursion, unless your algorithm is inherently recursive (in-order tree traversal, for example). This will make the code easier to write, read, and understand. Right now, I don't even feel like debugging your code, but it looks like your Store2 would never be bound to an integer, and is always going to be an unbound variable, no matter what input your program has.
Now to your program. It is not clear what you are trying to achieve. If you only want to evaluate list of the form [Arithmetic_operator, Operand1, Operand2], it would be much easier to write:
arith_eval(Expression_list, Result) :-
Arithmetic_expr =.. Expression_list, % look up what =.. stands for!
Result is Arithmetic_expr.
I don't see the need for this overly complicated approach you are using.
If you want to be able to evaluate arbitrarily complex expressions, written in post-fix, with fixed operator arity (so you can say 2, 3, +, but not 2, 4, 1, +, for a sum of 7):
Read one element from your input
Push the element to the top of the stack
Try to reduce the stack:
pop operator and operands, if on top of the stack
evaluate
push result back on the top of the stack
When input is empty, your stack is your result
You could explicitly define the effect of different operators (here, only + and -) like this:
eval_stack([+,A,B|Tail],[Result|Tail]) :-
number(A), number(B),
!,
Result is B + A.
eval_stack([-,A,B|Tail],[Result|Tail]) :-
number(A), number(B),
!,
Result is B - A.
eval_stack(Stack,Stack).
Note how either an operator matches the top of your stack, and is applied when there are operands below it, pushing the result back on the stack, or the stack is left unchanged.
And you can push from your input to your stack:
evaluate([Next|Rest], Stack, Result) :-
eval_stack([Next|Stack],NewStack),
evaluate(Rest,NewStack,Result).
evaluate([],Result,Result). % end of input
So now you could call this with:
?- evaluate([2,3,+,3,6,-,+],[],Result).
Result = [2].
?- evaluate([2,3,4,-,-,5,+],[],Result).
Result = [8].
?- evaluate([2,3,4,-,-,5,+,1,3,2,-],[],Result).
Result = [1,1,8].
So these two predicates, evaluate(Input,Stack,Result), and eval_stack(Stack,NewStack) is all you would need for evaluating a valid post-fix arithmetic expressions with fixed-arity operators only.

Checking for concatenation in Prolog

This is another prolog task that I can't solve at this moment. I have to write a predicat p(X,Y), where X is list of lists of number and Y is a list of numbers. The predicat has to verify:
1) if X can be presented as a concatenation between 2 elements from Y.
2) X has a odd number of elements.
3) Sum of all elements in X is last element in Y.
Maybe as a separate tasks 2, 3 could be written easy. Problem is at 1)
Thank you in advance. I feel sorry for posting such an easy tasks, but prolog really drives me crazy. I have read all my lections over and over again. But the situation is similar to this:
school: 3+x=5, x = ?
exam: cos(x+y+z) + lim (5x+y)/t = .... If you know what I mean. Thank you once again!
Checking for concatenations is done with append/3, which is more commonly used to build them but like many Prolog predicates works "in the opposite direction" as well. More specifically, append(A,B,C) checks whether C is the concatenation of A and B. So,
member(A, Y),
member(B, Y),
append(A, B, X)
checks whether there is a element A in Y and a element B in Y such that their concatenation unifies with X.
(Note that this does not check whether A and B are distinct elements of Y.)

Prolog length of a list

How can I calculate the length of a list
?- size_sub([[b,a,g], [9,3,7,4], [6]], X).
X = [3, 4, 1].
?- size_sub([[c,g,e,w], [7]], X).
X = [4, 1].
?- size_sub([], X).
X = [].
Ok you need to start with the base case which is the last answer
so size_sub([],X). is true if X=[] so first you write that as a rule.
size_sub([],[]).
Then you need to do the inductive step a list that is one longer than the previous. I am going to assume that you have a size/2 function for determining the size of a single list (if not please comment).
So the inductive step is going to operate on the length of the first parameter so N->N+1. We would represent this by striping off the head of the list syntax will be [H|T] now the second parameter (your answer) is going to be the length of H with the result of calling size_sub on T. As we cannot specify rules in the parameters in the header we will use N to represent the length of H and T2 to represent the result of size_sub on T.
So the first part of the rule becomes size_sub([H|T],[N|T2]):-
now we follow it with the predicates that will assert the values for N and T2.
size(H,N),
size_sub(T,T2).
putting that all together you get
size_sub([],[]).
size_sub([H|T],[N|T2]):-
size(H,N),
size_sub(T,T2).
size/2 is a far simpler case and following the same process of base + inductive you should be able to create the rules for it. Please comment if you need further help.
** EDIT - Request for size/2 definition **
To define size/2
Start with the base case, the empty list has a size of 0.
size([],0).
Now the inductive step. The size of list of length(N+1) is the size of a list of length(N). So lets define our list as [_|T] I've defined the list using _ to represent the head because we never use it so we can just use the anonymous variable. Lets use N to represent the length of T, and M to be N+1.
so
size([_|T],M):-
now lets define N
size(T,N),
and finally assert that M is equal to N + 1
M is N+1.
so putting everything together
size([],0).
size([_|T],N):-
size(T,M),
N is M+1.
size_sub([],[]).
size_sub([H|T],[N|T2]):-
size(H,N),
size_sub(T,T2).
To map length/2 over a list of lists, we can use the meta-predicate maplist/3 like this:
size_sub(Xss,Ls):-
maplist(length,Xss,Ls).