Deterministically finding last element of a list in Prolog - prolog

Finding the last element of a list in Prolog seems to be straightforward
my_last([A], A).
my_last([_,A|T], E) :-
my_last([A|T], E).
Unfortunately, this predicate is non-deterministic, no matter how "instantiated" the actual parameters are.
?- my_last([1,2,3], 3).
true ;
false.
Looking at the implementation of the nth0/3 here https://github.com/mthom/scryer-prolog/blob/master/src/lib/lists.pl, there's a "trick" to guard the actual predicates with integer(N) -> which acts like a preprocessor and splits the predicate into a deterministic and a non-deterministic branches.
So how do I define such preprocessor conditions for my_last/2, in order to make it deterministic for the case where the tail of the list is not a variable? Can it be done efficiently?

Can see swi-prolog's code:
?- listing(last).
lists:last([X|Xs], Last) :-
last_(Xs, X, Last).
?- listing(last_).
lists:last_([], Last, Last).
lists:last_([X|Xs], _, Last) :-
last_(Xs, X, Last).
This is using empty list [] vs head-and-tail [Head|Tail] distinction in the first argument, to be deterministic. More info at Determining if a list is empty or not

Related

How to tell Prolog that two literals are equivalent

Anyone knows how to tell Prolog that n(n(p)) and n(p) represent the same thing?
Or how to reduce n(n(p)) to n(p)?
Anyone knows how to tell Prolog that n(n(p)) and n(p) represent the same thing?
Prolog's unification system has a clear meaning of when two things are the same. n(n(p)) and n(p) are not the same thing. You can construct a predicate that defines a more generic equivalence relation than (=)/2.
Normally in Prolog two constants are different if they have a different name. Two compound terms are the same only if the functor is the same (the name of the functor and the number of parameters), and the parameters are equal as well.
We thus can define a predicate like:
equiv_(n(n(p)), n(p)).
equivalence(L, R) :-
equiv_(L, R).
equivalence(L, R) :-
equiv_(R, L).
equivalence(L, L).
If you the match with equivalence(n(n(p)), n(p)), it will return true.
#false Can't I define a predicate n(n(p)) that returns n(p). What I want, in fact, is that all occurrences of the within a list to be replaced with the latter.
You can make a predicate that unifies a second parameter with n(p) if the first one is n(n(p)):
replace_nnp(X, n(p)) :-
X == n(n(p)).
replace_nnp(X, X) :-
X \== n(n(p)).
Then we can use maplist/3 [swi-doc] to map a list of items to another list of items:
replace_nnp_list(LA, LB) :-
maplist(replace_nnp, LA, LB).
For example:
?- replace_nnp_list([n(n(p)), p, n(p), n(n(p))], X).
X = [n(p), p, n(p), n(p)] ;
false.

Append returning false

I have the following rule in prolog where each constant in the formula (a constant is defined as c(a)) is added to a list of constants however, my append statement continually returns false.
getCONSTs( tt, []).
getCONSTs( ff, []).
getCONSTs( c(C), [C]).
getCONSTs( and(Q1, Q2), ListConstants) :-
append(getCONSTs(Q1,A1),getCONSTs(Q2,A2),L1).
In the above append statement, if I give the rule a query such as:
?- getCONSTs(and(c(A),c(B)),[]).
The append statement should make a list of the constants: [A,B]
What you here aim to do is calling append/3 with as first two parameters terms with functor getCONSTs/2, so these are not lists. Sure there exists a predicate with the same name, but note that even if Prolog would call the predicate, it could only retrurn true or false (or raise an error, or get stuck in an infinite loop). But even calling the predicate is not happening: you construct a term, and it is more "coincidence" that there exists a predicate with the same name.
In Prolog one passes values by unifying variables with values, and then calling another predicate with that variable, like:
getCONSTs(and(Q1, Q2), L) :-
getCONSTs(Q1, A1),
getCONSTs(Q2, A2),
append(A1, A2, L).
Note that a call with:
?- getCONSTs(and(c(A),c(B)), []).
false.
still results in false, since here you basically query if "Is getConsts of and(c(A), c(B)) equal to []?". In order to generate a list, you should again use a variable, like:
?- getCONSTs(and(c(A),c(B)), L).
L = [A, B].

How palindrome check in prolog works? [duplicate]

Can I get a recursive Prolog predicate having two arguments, called reverse, which returns the inverse of a list:
Sample query and expected result:
?- reverse([a,b,c], L).
L = [c,b,a].
A recursive Prolog predicate of two arguments called palindrome which returns true if the given list is palindrome.
Sample query with expected result:
?- palindrome([a,b,c]).
false.
?- palindrome([b,a,c,a,b]).
true.
Ad 1: It is impossible to define reverse/2 as a (directly edit thx to #repeat: tail) recursive predicate - unless you permit an auxiliary predicate.
Ad 2:
palindrome(X) :- reverse(X,X).
But the easiest way is to define such predicates with DCGs:
iseq([]) --> [].
iseq([E|Es]) --> iseq(Es), [E].
reverse(Xs, Ys) :-
phrase(iseq(Xs), Ys).
palindrome(Xs) :-
phrase(palindrome, Xs).
palindrome --> [].
palindrome --> [E].
palindrome --> [E], palindrome, [E].
There isn't an efficient way to define reverse/2 with a single recursive definition without using some auxiliary predicate. However, if this is nevertheless permitted, a simple solution which doesn't rely on any built-ins like append/3 (and should be applicable for most Prolog implementations) would be to use an accumulator list, as follows:
rev([],[]).
rev([X|Xs], R) :-
rev_acc(Xs, [X], R).
rev_acc([], R, R).
rev_acc([X|Xs], Acc, R) :-
rev_acc(Xs, [X|Acc], R).
rev/2 is the reversal predicate which simply 'delegates' to (or, wraps) the accumulator-based version called rev-acc/2, which recursively adds elements of the input list into an accumulator in reverse order.
Running this:
?- rev([1,3,2,x,4],L).
L = [4, x, 2, 3, 1].
And indeed as #false has already pointed out (+1),
palindrome(X) :- rev(X,X).
Just for curiosity here goes a recursive implementation of reverse/2 that does not use auxiliary predicates and still reverses the list. You might consider it cheating as it uses reverse/2 using lists and the structure -/2 as arguments.
reverse([], []):-!.
reverse([], R-R).
reverse(R-[], R):-!.
reverse(R-NR, R-NR).
reverse([Head|Tail], Reversed):-
reverse(Tail, R-[Head|NR]),
reverse(R-NR, Reversed).
conca([],L,L).
conca([X|L1],L2,[X|L3]):- conca(L1,L2,L3).
rev([],[]).
rev([X|Y],N):- rev(Y,N1),conca(N1,[X],N).
palindrome([X|Y]):- rev([X|Y],N),equal([X|Y],N).
equal([X],[X]).
equal([X|Y],[X|Z]):- equal(Y,Z).

Matching tuples in Prolog

Why does Prolog match (X, Xs) with a tuple containing more elements? An example:
test2((X, Xs)) :- write(X), nl, test2(Xs).
test2((X)) :- write(X), nl.
test :-
read(W),
test2(W).
?- test.
|: a, b(c), d(e(f)), g.
a
b(c)
d(e(f))
g
yes
Actually this is what I want to achieve but it seems suspicious. Is there any other way to treat a conjunction of terms as a list in Prolog?
Tuple term construction with the ,/2 operator is generally right-associative in PROLOG (typically referred to as a sequence), so your input of a, b(c), d(e(f)), g might well actually be the term (a, (b(c), (d(e(f)), g))). This is evidenced by the fact that your predicate test2/1 printed what is shown in your question, where on the first invocation of the first clause of test2/1, X matched a and Xs matched (b(c), (d(e(f)), g)), then on the second invocation X matched b(c) and Xs matched (d(e(f)), g), and so on.
If you really wanted to deal with a list of terms interpreted as a conjunction, you could have used the following:
test2([X|Xs]) :- write(X), nl, test2(Xs).
test2([]).
...on input [a, b(c), d(e(f)), g]. The list structure here is generally interpreted a little differently from tuples constructed with ,/2 (as, at least in SWI-PROLOG, such structures are syntactic sugar for dealing with terms constructed with ./2 in much the same way as you'd construct sequences or tuple terms with ,/2). This way, you get the benefits of the support of list terms, if you can allow list terms to be interpreted as conjunctions in your code. Another alternative is to declare and use your own (perhaps infix operator) for conjunction, such as &/2, which you could declare as:
:- op(500, yfx, &). % conjunction constructor
You could then construct your conjunct as a & b(c) & d(e(f)) & g and deal with it appropriately from there, knowing exactly what you mean by &/2 - conjunction.
See the manual page for op/3 in SWI-PROLOG for more details - if you're not using SWI, I presume there should be a similar predicate in whatever PROLOG implementation your'e using -- if it's worth it's salt :-)
EDIT: To convert a tuple term constructed using ,/2 to a list, you could use something like the following:
conjunct_to_list((A,B), L) :-
!,
conjunct_to_list(A, L0),
conjunct_to_list(B, L1),
append(L0, L1, L).
conjunct_to_list(A, [A]).
Hmm... a, b(c), d(e(f)), g means a and (b(c) and (d(e(f)) and g)), as well list [1,2,3] is just a [1 | [2 | [3 | []]]]. I.e. if you turn that conjuction to a list you'll get the same test2([X|Xs]):-..., but difference is that conjunction carries information about how that two goals is combined (there may be disjunction (X; Xs) as well). And you can construct other hierarchy of conjunctions by (a, b(c)), (d(e(f)), g)
You work with simple recursive types. In other languages lists is also recursive types but they often is pretending to be arrays (big-big tuples with nice indexing).
Probably you should use:
test2((X, Y)):- test2(X), nl, test2(Y).
test2((X; Y)). % TODO: handle disjunction
test2(X) :- write(X), nl.

Prolog difference routine

I need some help with a routine that I am trying to create. I need to make a routine that will look something like this:
difference([(a,b),(a,c),(b,c),(d,e)],[(a,_)],X).
X = [(b,c),(d,e)].
I really need help on this one..
I have written a method so far that can remove the first occurrence that it finds.. however I need it to remove all occurrences. Here is what I have so far...
memberOf(A, [A|_]).
memberOf(A, [_|B]) :-
memberOf(A, B).
mapdiff([], _, []) :- !.
mapdiff([A|C], B, D) :-
memberOf(A, B), !,
mapdiff(C, B, D).
mapdiff([A|B], C, [A|D]) :-
mapdiff(B, C, D).
I have taken this code from listing(subtract).
I don't fully understand what it does, however I know it's almost what I want. I didn't use subtract because my final code has to be compatible with WIN-Prolog... I am testing it on SWI Prolog.
Tricky one! humble coffee has the right idea. Here's a fancy solution using double negation:
difference([], _, []).
difference([E|Es], DL, Res) :-
\+ \+ member(E, DL), !,
difference(Es, DL, Res).
difference([E|Es], DL, [E|Res]) :-
difference(Es, DL, Res).
Works on SWI-PROLOG. Explanation:
Clause 1: Base case. Nothing to diff against!
Clause 2: If E is in the difference list DL, the member/2 subgoal evaluates to true, but we don't want to accept the bindings that member/2 makes between variables present in terms in either list, as we'd like, for example, the variable in the term (a,_) to be reusable across other terms, and not bound to the first solution. So, the 1st \+ removes the variable bindings created by a successful evaluation of member/2, and the second \+ reverses the evaluation state to true, as required. The cut occurs after the check, excluding the 3rd clause, and throwing away the unifiable element.
Clause 3: Keep any element not unifiable across both lists.
I am not sure, but something like this could work. You can use findall to find all elements which can't be unified with the pattern:
?- findall(X, (member(X, [(a,b),(b,c),(a,c)]), X \= (a,_)), Res).
gets the reply
Res = [ (b, c) ]
So
removeAll(Pattern, List, Result) :-
findall(ZZ109, (member(ZZ109, List), ZZ109 \= Pattern), Result).
should work, assuming ZZ109 isn't a variable in Pattern (I don't know a way to get a fresh variable for this, unfortunately. There may be a non-portable one in WIN-Prolog). And then difference can be defined recursively:
difference(List, [], List).
difference(List, [Pattern|Patterns], Result) :-
removeAll(Pattern, List, Result1),
difference(Result1, Patterns, Result).
Your code can be easily modified to work by making it so that the memberOF predicate just checks to see that there is an element in the list that can be unified without actually unifying it. In SWI Prolog this can be done this way:
memberOf(A, [B|_]) :- unifiable(A,B,_).
But I'm not familiar with WIN-PRolog so don't know whether it has a predicate or operator which only tests whether arguments can be unified.

Resources