how to set value of an arg in Prolog? - prolog

I have an assignment question like so:
Write a program to find the last element of a list. e.g.
?- last(X, [how, are, you]).
X = you
Yes
I'm currently finding the last element like this:
last([Y]) :-
write('Last element ==> '),write(Y).
last([Y|Tail]):-
last(Tail).
And it works. My question is, how do I change it to accept and set the addition X parameter and set it correctly?
I tried this, but it's not working ...
last(X, [Y]) :-
X is Y.
last(X, [Y|Tail]):-
last(X, Tail).

Most obvious problem: (is)/2 works with numbers only. (link)
-Number is +Expr
True when Number is the value to which Expr evaluates
You want to use the unification operator (=)/2 (link):
last(X, [Y]) :-
X = Y,
!.
last(X, [_|Tail]):-
last(X, Tail).
Let's try:
?- last(X, [1, 2, 3]).
X = 3.
?- last(X, [a, b, c]).
X = c.

Using the unification operator is not the preferred way to unify in a case like this. You can use unification in a much more powerful way. See the following code:
last(Y, [Y]). %this uses pattern matching to Unify the last part of a list with the "place holder"
%writing this way is far more concise.
%the underscore represents the "anonymous" element, but basically means "Don't care"
last(X, [_|Tail]):-
last(X, Tail).

Related

Is it possible to write an inconsistent Prolog program using only pure Prolog, cut and `false`?

This one tickled my interest in theory:
Is it possible to write an inconsistent Prolog program, i.e. a program that answers both false and true depending on how it is queried, using only pure Prolog, the cut, and false?
For example, one could query p(1) and the Prolog Processor would says false. But when one queries p(X) the Prolog Processor would give the set of answers 1, 2, 3.
This can be easily achieved with "computational state examination predicates" like var/1 (really better called fresh/1) + el cut:
p(X) :- nonvar(X),!,member(X,[2,3]).
p(X) :- member(X,[1,2,3]).
Then
?- p(1).
false.
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
"Ouch time" ensues if this is high-assurance software. Naturally, any imperative program has no problem going off the rails like this on every other line.
So. can be done without those "computational state examination predicates"?
P.S.
The above illustrates that all the predicates of Prolog are really carrying a threaded hidden argument of the "computational state":
p(X,StateIn,StateOut).
which can be used to explain the behavour of var/1 and friends. The Prolog program is then "pure" when it only calls predicates that neither consult not modify that State. Well, at least that seems to be a good way to look at what is going on. I think.
Here's a very simple one:
f(X,X) :- !, false.
f(0,1).
Then:
| ?- f(0,1).
yes
| ?- f(X,1).
no
| ?- f(0,Y).
no
So Prolog claims there are no solutions to the queries with variables, although f(0,1) is true and would be a solution to both.
Here is one attempt. The basic idea is that X is a variable iff it can be unified with both a and b. But of course we can't write this as X = a, X = b. So we need a "unifiable" test that succeeds without binding variables like =/2 does.
First, we need to define negation ourselves, since it's impure:
my_not(Goal) :-
call(Goal),
!,
false.
my_not(_Goal).
This is only acceptable if your notion of pure Prolog includes call/1. Let's say that it does :-)
Now we can check for unifiability by using =/2 and the "not not" pattern to preserve success while undoing bindings:
unifiable(X, Y) :-
my_not(my_not(X = Y)).
Now we have the tools to define var/nonvar checks:
my_var(X) :-
unifiable(X, a),
unifiable(X, b).
my_nonvar(X) :-
not(my_var(X)).
Let's check this:
?- my_var(X).
true.
?- my_var(1).
false.
?- my_var(a).
false.
?- my_var(f(X)).
false.
?- my_nonvar(X).
false.
?- my_nonvar(1).
true.
?- my_nonvar(a).
true.
?- my_nonvar(f(X)).
true.
The rest is just your definition:
p(X) :-
my_nonvar(X),
!,
member(X, [2, 3]).
p(X) :-
member(X, [1, 2, 3]).
Which gives:
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
?- p(1).
false.
Edit: The use of call/1 is not essential, and it's interesting to write out the solution without it:
not_unifiable(X, Y) :-
X = Y,
!,
false.
not_unifiable(_X, _Y).
unifiable(X, Y) :-
not_unifiable(X, Y),
!,
false.
unifiable(_X, _Y).
Look at those second clauses of each of these predicates. They are the same! Reading these clauses declaratively, any two terms are not unifiable, but also any two terms are unifiable! Of course you cannot read these clauses declaratively because of the cut. But I find this especially striking as an illustration of how catastrophically impure the cut is.

(Prolog) the first solution from the list that satisfies the goal

I need to find the first element on the list which satisfies a user provided goal. I mean something like maplist/2 but which succeeds when the goal can be applied to at least one element. include/3 would be an option but I'm after a more optimal solution that can stop after finding the first element.
I think the interface could look like:
first(:Goal, List, First)
and it should be semidet in the SWI-Prolog sense.
It's fairly easy to code it but I'd prefer an existing rule. Is there a relevant rule in the "standard" libraries; I'm using SWI-Prolog.
Cheers,
Jacek
I don't think there's a standard predicate that does this. But as you say, it would be very easy to code. I would probably write something like this, which has a pattern like the member/2 predicate:
includes_item(Goal, [X|_], X) :-
call(Goal, X).
includes_item(Goal, [_|T], X) :-
includes_item(Goal, T, X).
As #false indicates in the comments, this in fact can be more clearly written using member/2:
includes_item(Goal, List, Item) :-
member(Item, List),
call(Goal, Item).
includes_item(:Goal, List, Item) succeeds for each Item in List that satisfies :Goal. For example:
3 ?- includes_item('>'(3), [1,2,3,-2, 4, 5], X).
X = 1 ;
X = 2 ;
X = -2 ;
false.
You can then use once/1 to obtain only the first item without a choice point:
first(Goal, List, Item) :-
once(includes_item(Goal, List, Item)).
And now you get:
4 ?- first('>'(3), [1,2,3,-2, 4, 5], X).
X = 1.
5 ?-

Prolog - Backtracking through a set of dynamic options

I'm trying to trigger backtracking on a goal but in a dynamic way, if it's possible. To better exemplify my issue let's say we have the following PROLOG code:
num(1).
num(2).
num(3).
num(4).
num(5).
Then I head to SWI-Prolog and call: num(X). This triggers backtracking looking for all solutions, by typing ; .
What I would like is to remove those facts (num(1),num(2), etc) and replace that code with something thata generates those facts dynamically. Is there any way in which I can achieve this? Someting of the sorts,maybe?
num(X):- for X in 1..5
that yields the same solutions as the code above?
As far as I know, the findall predicate returns a list, which is not what I'm looking for. I would like to backtrack through all answers and look through them using ; in the console.
Yes there is, and you were already very close!
:- use_module(library(clpfd)).
num(X) :-
X in 1..5.
?- num(X).
X in 1..5.
?- num(X), X #>3.
X in 4..5.
?- num(X), labeling([], [X]).
X = 1
; X = 2
; X = 3
; X = 4
; X = 5.
SWI-Prolog has the (non-ISO) predicate between/3 for that:
num(X) :- between(1, 5, X).
You can implement the predicate (for other Prologs and for further tweaking) like this:
between2(A, A, A) :- !. % green cut
between2(A, B, A) :- A < B.
between2(A, B, C) :-
A < B,
A1 is A + 1,
between2(A1, B, C).
The signature for both between/3 and between2/3 is (+From,+To,?X). It means that the From and To must be bound and X can be either bound or not. Also note that From and To must be integers such that From <= To. (Oh, and these integers must be written using Arabic numerals with an optional plus or minus sign before. And using ASCII. Is something non-obvious still missed? And the integers must not be too large or too small, although SWI-Prolog is usually compiled with unbounded integer support, so both between(1, 100000000000000000000000000000000000000000000, X) and between2(1, 100000000000000000000000000000000000000000000, X) usually work.)

Using repeat to sort a collection of facts in prolog

I have a set of facts set/2 where the first variable is the identifier for the set and the second is the value associated with the identifier.
For example:
set(a,2).
set(a,c).
set(a,1).
set(a,a).
set(a,3).
set(a,b).
I need to construct a predicate ordering/2 (using the repeat operator) which will output the values of a specific set in their lexicographic order.
For example
?- ordering(a,Output).
Would result in
[1,2,3,a,b,c].
What I have made thus far is this code:
ordering(Input,Output):-
findall(X,set(Input,X),List),
repeat,
doSort(List)
sort(List, OrderedList),
Output = OrderedList.
The idea here is that the predicate will find all values of the set associated with the specific Input and unify the List variable with them. Now we have the unsorted List. Here comes the part I'm not completely sure on. The predicate is supposed to keep using some sort of specific doSort on the List, then check the List with sort/2 and if it's lexicographically ordered, unify it with the Output.
Can anyone clarify if I'm on the correct path and if yes then how should the doSort be implemented?
Alright, I tried a sort of answer for this using #Daniel lyon's help:
ordering(Input,Output):-
findall(X,set(Input,X),List),
repeat,
permutation(List,PermutationList),
sort(PermutationList, SortedList),
Output= SortedList , !.
The general idea is the same, for the repeat cycle, the predicate will unify the List with PermutationList, try all variants of it and check for their correctness with sort/2 until it achieves the correct permutation, unifying it with SortedList, after that it will unify the Output with SortedList. The cut is there so I will only get the Output once.
?- % init test DB
| maplist([X]>>assert(set(a,X)), [c,b,a,1,2,3]).
true.
?- % find first
| set(a,X), \+ (set(a,Y), Y #< X).
X = 1 ;
false.
?- % find next, given - hardcoded here as 1 - previous
| set(a,X), X #> 1, \+ (set(a,Y), Y #> 1, Y #< X).
X = 2 ;
false.
now we can try to make these queries reusable:
ordering(S,[H|T]) :- first(S,H), ordering(S,H,T).
first(S,X) :- set(S,X), \+ (set(S,Y), Y #< X).
next(S,P,X) :- set(S,X), X #> P, \+ (set(S,Y), Y #> P, Y #< X).
ordering(S,P,[X|T]) :- next(S,P,X), ordering(S,X,T).
ordering(_,_,[]).
To be correct, we need a cut somewhere. Can you spot the place ?

Prolog List Squaring, Modifying element in List

I am trying to write a short Prolog program which takes a list of numbers and returns a list where all numbers have been squared.
Ie: [2,4,5] => [4,16,25]
My code so far:
list_of_squares([X], L) :-
L is X^2.
list_of_squares([X|XS], [X^2|M]) :-
list_of_squares(XS, M).
For some reason though Prolog doesn't like me squaring X while adding it to a list... Any thoughts on how I could do this?
You're not that far off, but you make two small mistakes:
Firstly, you mix element X with list L. Your first clause should be:
list_of_squares([X], [Y]):-
Y is X ^ 2.
Secondly, you cannot perform an arithmetic function in list notation.
Your second clauses should be as follows:
list_of_squares([X|Xs], [Y|Ys]):-
Y is X ^ 2,
list_of_squares(Xs, Ys).
Thirdly, there is a more fundamental problem. With the first two fixes, your code works, but the base case, i.e. the first clause, is not that well chosen. (A) the code cannot process the empty list. (B) For a singleton list the code is needlessly nondeterministic, because both clauses apply. This is solved by choosing the base case wisely:
squares([], []).
squares([X|Xs], [Y|Ys]):-
Y is X ^ 2,
squares(Xs, Ys).
Here is a general method how you can localize such an error. First, let's start with your exemple:
?- list_of_squares([2,4,5],[4,16,25]).
false.
Oh no! It fails! There is a very general method what to do in such a situation:
Generalize the query
So we replace [4,16,25] by a new, fresh (ah, true freshness!) variable:
?- list_of_squares([2,4,5],L).
L = [2^2,4^2|25]
; false.
That's way better: Now you know that there is a "result", but that result it not what you expected.
Next,
Minimize the query
The list is way too long, so I will chop off some elements. Say, the first two:
?- list_of_squares([5],L).
L = 25
; false.
Again, wrong, but smaller. Now, where is the error for that? To get it
Specialize your program
list_of_squares([X], L) :-
L is X^2.
list_of_squares([X|XS], [X^2|M]) :- false,
list_of_squares(XS, M).
That program, again gives the same wrong answer! So in there is a bug in the visible part. What we expect is
?- list_of_squares([5],[25]).
false.
this to succeed. But where is the error? Again:
Generalize the query
?- list_of_squares([5],[X]).
false.
HET!
Now, you should realize that that rule might be:
list_of_squares([X], [Y]):-
Y is X ^ 2.
And the same (is)/2 should be used in the recursive rule. And, why not accept [].
I, personally, would rather write using library(lambda):
list_of_squares(Xs, Ys) :-
maplist(\X^XX^(XX is X^2), Xs, Ys).
Or, even better, using library(clpfd)
list_of_squares(Xs, Ys) :-
maplist(\X^XX^(XX #= X^2), Xs, Ys).
Prolog doesn't have a 'functional' mindset, but some standard builtin predicate can help working with lists. In this case
list_of_squares(L,S) :- findall(Sq,(member(E,L),Sq is E*E),S).
?- list_of_squares([2,4,5], R).
R = [4, 16, 25].
in this case, member/2 play a role similar to lambda expressions, giving a 'name' to each element E available in L. findall/3 compute all solutions of its goal ,(member(E,L),Sq is E*E),, and collects results (the 'template' expression, that is, Sq).

Resources