Rename Variables in SWI Prolog - prolog

How can I rename variables in SWI Prolog?
I tried to use numbervars predicate like this.
numbervars(Xs,1,_,[functor_name(name)]).
So if Xs is a list of 4 variables, it will look like this when I commit 'writeln(Xs)'.
[name(1),name(2),name(3),name(4)]
How can I use that functor, or any other way to remove the parenthesis and make it looks like:
[name1,name2,name3,name4]
Thanks in advance.

You can write your own subset of numbervars/4 (or completely rewrite your own, if you wish). Here's a subset that performs the specific task you're describing:
build_atoms([Var|VarList], N, Prefix) :-
atom_number(Atom, N),
atom_concat(Prefix, Atom, Var),
N1 is N + 1,
build_atoms(VarList, N1, Prefix).
build_atoms([], _, _).
This accepts a list of variables and instantiates them in sequence with the atom given in Prefix contactenated with integers, starting with N.
For example:
?- X = [A,B,C], build_atoms(X, 1, foo).
X = [foo1, foo2, foo3],
A = foo1,
B = foo2,
C = foo3.
?-
This can easily be expanded to include any other functionality in numbervars that you desire.

Related

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

Prolog combining predicates

Just a small question about Prolog. Say I have used the built in predicate findall/3 to obtain a list and used the variable X as my output.
I'm wondering how I could then use this list in another predicate such as last/2 to find the last element of this list. If you could include a small example too that would help greatly.
First of all, since Prolog aims to be a logic programming programming language, there is nu such thing as output variables.
Nevertheless, say you know a variable X is bounded after a certain predicate and you intend to use this value when calling a new predicate, you can use Prolog's logical "and" ,/2. I'm putting "and" between quotes because this and differs sometimes from the natural understanding of how "and" in natural language behaves.
You can thus use a predicate:
findall(A,foo(A),X),last(X,L).
To first find all occurences of foo/1, extract the variable A, put these into a list X and finally get the last/2 element of X.
You can then for instance use this in a defined predicate:
last_foo(L) :-
findall(A,foo(A),X),
last(X,L).
If you run this for instance with:
foo(a).
foo(9).
foo(b).
The results are:
?- foo(A).
A = a ;
A = 9 ;
A = b.
and:
?- findall(A,foo(A),X).
X = [a, 9, b].
Now the result to obtain the last is:
?- findall(A,foo(A),X),last(X,L).
X = [a, 9, b],
L = b.
or:
?- last_foo(L).
L = b.

Checking that a list contains only zeros

I have been given a question in my assignment that asks to write a Prolog program that takes as input a list of numbers and succeeds if the list
contains only 0s.
I am having trouble on how to make the program search for zeroes. For example, a query like:
?- zero([0,0,0,0]).
Should give us true and it should return false whenever there's a number other than zero in it.
Usually, one would not define a proper predicate for this, but rather use maplist/2 for the purpose:
..., maplist(=(0), Zs), ...
To give a concrete example:
?- Zs =[A,B,C], maplist(=(0), Zs).
This query corresponds to:
?- Zs = [A,B,C], call(=(0), A), call(=(0), B), call(=(0), C).
or even simpler:
?- Zs = [A,B,C], 0 = A, 0 = B, 0 = C.
If you want to define this as a separate predicate, remember to use a good name for it. Each element of the list is a zero, and the relation describes the entire list of such zeros. The convention for lists in this case is to use the plural word. Thus zeros/1:
zeros([]).
zeros([0|Zs]) :-
zeros(Zs).
why are you asking us to do your homework for you?
anyway, it's very simple recursion. something like:
zero([]).
zero([0|T]) :- zero(T).
just keep peeling of zero's until your list is empty. it isn't so hard ;)

Why prolog outputs a weird tree-like list?

In this Prolog code I intend to list the first N primes,
(...)
biggerPrime(N,P) :-
isPrime(N),
P is N,
!.
biggerPrime(N,P) :-
N1 = N+1,
biggerPrime(N1,P).
primeListAcc(0,A,R,R) :- !.
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[P|L],R).
And it works fine if I want the list ordered backwards:
?- primeList(5,L).
L = [11, 7, 5, 3, 2].
But if I change the last line of the code from [P|L] to [L|P] like this:
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[L|P],R).
I get:
?- primeList(5,L).
L = [[[[[[]|2]|3]|5]|7]|11].
What am I missing? This is driving me mad!
Recall that a list is either the empty list [] or a term with functor '.' and two arguments, whose second argument is a list. The syntax [P|Ps] is shorthand notation for the term '.'(P, Ps), which is a list if Ps is a list (as is the case in your example). The term '.'(Ps, P), on the other hand, which can also be written as [Ps|P] (as you are doing), is not a list if P is not a list. You can obtain a reverse list with reverse/2.
Great, so you've discovered the problem of adding elements to the end of a list. In Prolog, we can do it with
add(X,L,Z):- L=[X|Z].
wait, what? How to read this? We must know the calling convention here. We expect L and Z to come in as uninstantiated variables, and we arrange for L from now on to point to a newly created cons node with X at its head, and Z its tail. Z to be instantiated, possibly, in some future call.
IOW what we create here is an open-ended list, L = [X|Z] = [X, ...]:
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,Z,L) :- N > 0, % make it explicitly mutually-exclusive,
N1 is N-1, % do not rely on red cuts which are easily
biggerPrime(A,P), % invalidated if clauses are re-arranged!
A1 is P+1,
L = [P|R], % make L be a new, open-ended node, holding P
primeListAcc(N1,A1,Z,R). % R, the tail of L, to be instantiated further
primeListAcc(0,A,R,R). % keep the predicate's clauses together
We can see now that Z is not really needed here, as it carries the [] down the chain of recursive calls, unchanged. So we can re-write primeListAcc without the Z argument, so that its final clause will be
primeListAcc(0,A,R):- R=[].
Keeping Z around as uninstantiated variable allows for it to be later instantiated possibly with a non-empty list as well (of course, only once (unless backtracking occurs)). This forms the basis of "difference list" technique.
To answer your literal question - here, consider this interaction transcript:
1 ?- X=[a|b].
X = [a|b]
2 ?- X=[a|b], Y=[X|c].
X = [a|b]
Y = [[a|b]|c]
the [a|b] output is just how a cons node gets printed, when its tail (here, b) is not a list. Atoms, as numbers, are not lists.

Prolog Subtract List Unification

I am trying to subtract one list from another in prolog. In my program the input list have blank spaces in them (e.g. [1,2,_,4])
I am getting the following output:
?- subtract([1,2,3,4],[3,4,_],L).
L = [2].
when I want my output to be
L = [1,2].
So my question is how can I prevent the blank spaces from unifying with other elements? Have been stuck on this for a while.
Assuming you want the "blank spaces" to be ignored, you can simply make a version of each list with those removed and compute their difference:
listWOblanks( [], [] ).
listWOblanks( [H|T], Tx ) :- var(H), !, listWOblanks( T, Tx ).
listWOblanks( [H|T], [H|Tx] ) :- listWOblanks( T, Tx ).
If, when the first list has a blank and the second does not, you need the result to still have a blank, you could modify the above to add a 3rd argument that tells you if any blanks were removed so you can correct the difference accordingly. I believe SWI-Prolog has a predicate, ground, which will tell you if a term has no variables in it, which would do the job w/o needing to modify listWOblanks.
larsmans is correct, the _ is an anonymous variable, and the definition of lists:subtract/3 (which I'm assuming you're using in SWI-Prolog) will always unify them to ground list members because of it's definition using memberchk/2.
If you want subtract behaviour where variables are to be treated like ground terms, then you can redefine it like this:
subtract2([], _, []) :- !.
subtract2([A|C], B, D) :-
var_memberchk(A, B), !,
subtract2(C, B, D).
subtract2([A|B], C, [A|D]) :-
subtract2(B, C, D).
Note that subtract2/3 here is nearly the same as the definition of lists:subtract/3 (try listing(subtract). to see for yourself). The only difference is the list membership predicate, var_memberchk/2, which is defined like this:
var_memberchk(A0, [A1|_]) :-
A0 == A1, !.
var_memberchk(A0, [_|R]) :-
var_memberchk(A0, R).
This checks to see if a variable, atom or term is in the list. So, trying this we get:
?- subtract2([1,2,3,4],[3,4,_],L).
L = [1, 2].
Note that it still works if we name the variables, as you'd expect:
?- subtract2([1,2,A,3,B,4],[3,A,4],L).
L = [1, 2, B].
It also works if we explicitly give names to anonymous variables, like this:
?- subtract2([1,2,_A,3,_B,4],[3,_A,4],L).
L = [1, 2, _B].
Finally, note that since _ doesn't have a name, subtract2/3 will never be able to match it to other anonymous variables in either list, for example:
subtract2([1,2,_,4],[3,_,4],L).
L = [1, 2, _G415].
Where _G415 is the anonymous global variable denoted by the _ in the first input list. The second is a different global variable (like _G416, for instance), so could never match the anonymous variable in the first list.
Another way:
% Uses list catenation to generate sublists /subtraction
conc([], L, L).
conc([X|L1], L2, [X|L3]) :-
conc(L1, L2, L3).
% Finds all list members that have values and then
% use list catenation to generate the sublists
subtract(L1, L2, L3) :-
findall(D, (nth0(N, L2, D), nonvar(D)), PureL2),
conc(L3, PureL2, L1).
This assumes that only one list has '_', but you could do the same findall for L1 if both lists have the same problem.

Resources