Predicate returns true and not some value - prolog

I am trying to make a predicate that takes two numbers K, Num (0 when you use the predicate, it changes after each recursion), a list containing numbers from 1 to K and an associative tree with all keys from 1 to K having values 0. When all numbers from 1 to K are found on the list (Num has the numbers found until then) it returns the rest of the list NL and an associative tree where the value of each key is the times each number is found. It should be used like this:
first(3, 0, [1,3,1,3,1,3,3,2,2,1], T, NL, NT)
where T is the tree described above.
Here is my code:
first(K, K, L, T, L, T):- !.
first(_, _, [], _, [], NT) :-
empty_assoc(NT), !.
first(K, Num, [H|L], T, NL, NT) :-
get_assoc(H, T, V),
Newv is V+1,
put_assoc(H, T, Newv, TT),
V=:=0 -> Newnum is Num+1; Newnum is Num,
first(K, Newnum, L, TT, NL, NT).
My problem is than it returns true instead of the values of NL and NT.

The main problem here is operator precedence. If we ask the interpreter to generate a listing., we get:
first(A, A, B, C, B, C) :- !.
first(_, _, [], _, [], A) :-
empty_assoc(A), !.
first(G, E, [A|H], B, I, J) :-
( get_assoc(A, B, C),
D is C+1,
put_assoc(A, B, D, _),
C=:=0
-> F is E+1
; F is E,
first(G, F, H, _, I, J)
).
This learns us that only in case C =:= 0 does not hold, we will make a recursive call to first/6. This is probably not your intention. Since we only make a recursive call in case the condition does not hold, the TT
If we use brackets, like:
first(K, K, L, T, L, T):- !.
first(_, _, [], _, [], NT) :-
empty_assoc(NT), !.
first(K, Num, [H|L], T, NL, NT) :-
get_assoc(H, T, V),
Newv is V+1,
put_assoc(H, T, Newv, TT),
(V=:=0 -> Newnum is Num+1; Newnum is Num),
first(K, Newnum, L, TT, NL, NT).
With that fixed, we obtain an error:
?- first(3, 0, [1,3,1,3,1,3,3,2,2,1], T, NL, NT)
| .
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [13] throw(error(instantiation_error,_7048))
ERROR: [9] assoc:get_assoc(1,_7080,_7082) at /usr/lib/swi-prolog/library/assoc.pl:178
ERROR: [8] first(3,0,[1,3|...],_7112,_7114,_7116) at /tmptest.pl:5
ERROR: [7] <user>
This means that we aim to call get_assoc/3, but with a non-constructed associative array. Note that the empty_assoc/1 is not constructed, it is only constructed at the end when the lists are exhausted.
I think the core problem here is that you are doing too much at once. We can make small predicates that each do limited work.
For example, we can generate an associative array that maps all values between 1 and K to 0 with:
gen_assoc(K, A) :-
empty_assoc(E),
gen_assoc(K, E, A).
gen_assoc(0, A, A).
gen_assoc(K, A, C) :-
K > 0,
put_assoc(K, A, 0, B),
K1 is K-1,
gen_assoc(K1, B, C).
So here gen_assoc(3, A) will unify A with an associative array that maps all numbers from 1 to 3 (both inclusive) to 0.
I leave the rest as an exercise.

Related

Intersection of two lists with duplicate elements

I am working on defining an intersection predicate, that takes in two lists, allowing duplicated elements. This is what I have so far.
intersection([], _, []).
intersection([H1|T1], L2, [H1|R]) :- m_member(H1, L2), intersection(T1, L2, R).
intersection([_|T1], L2, R) :- intersection(T1, L2, R).
However, in the case of the follows:
intersection([a,b,b,a],[c,b,b,c,e,f], S).
The predicate-call returns [b, b]. I would like to return [b] instead. Any pointers?
A possible solution to obtain the intersection D of [X|A] and B is:
Suppose, as induction hypothesis, that the intersection of A and B is C (without repetition).
Therefore:
if X is member of C or X is not member of B, then D is equal to C;
otherwise, D is equal to [X|C].
% inter(++Set1, ++Set2, -Set3)
inter([], _, []).
inter([X|A], B, D) :-
inter(A, B, C),
( ( memberchk(X, C)
; \+ memberchk(X, B) )
-> D = C
; D = [X|C] ).
Example:
?- inter([a,b,b,a], [c,b,b,c,e,f], S).
S = [b].

print out letter squences in prolog

I have to write out a program in Prolog that prints out letter sequences, Implement in Prolog a predicate twist/2 for ‘twisting’ pairs of entries of a list and discarding the entries in between. More precisely,
• Interchange the 1st and 2nd entries,
• Discard the 3rd entry,
• Interchange the 4th and 5th entries,
• Discard the 6th entry and so on as follows:
twist([’B’,r,a,d,f,o,r,d], T)--->
twist([’B’,r,a,d,f,o,r,d], [], y, T)--->
twist([a,d,f,o,r,d], [’B’,r], n, T)--->
twist([d,f,o,r,d], [’B’,r], y, T)--->
twist([o,r,d], [d,f,’B’,r], n, T)--->
twist([r,d], [d,f,’B’,r], y, T)--->
twist([], [r,d,d,f,’B’,r], n, T)--->
reverse([r,d,d,f,’B’,r], T)--->
T = [r,’B’,f,d,d,r] ---> success
So far I have:
twist(L,T) :-
twist(L, [], y, T). % clause 0: invoke auxiliary predicate
twist([], Acc, L) :- reverse(Acc, L),
twist(A,G,_|T), Acc, L) :- twist(T,[A,G|Acc], L),
twist([A,G], Acc, L) :- twist([],[A,G|Acc], L),
twist([], Acc, L) :- reverse(Acc, L).
I'm sure that's right but i keep getting the same error.
here's the full error message:
4 ?- twist([b, r ,a ,d ,f ,o ,r ,d], T).
ERROR: twist/2: Undefined procedure: twist/4
ERROR: However, there are definitions for:
ERROR: twist/2
Exception: (7) twist([b, r, a, d, f, o, r, d], [], y, _G2583) ?
Any help would be great.
try this:
twist([],[]).
twist([X],[X]).
twist([X,Y],[Y,X]).
twist([X,Y,_|Tail],[Y,X|NewTail]):- twist(Tail, NewTail).
And then ask:
?- twist([b, r ,a ,d ,f ,o ,r ,d], T).
T = [r, b, f, d, d, r] ;
false.
credits go to #lurker.

List in certain range

I have a predicate that is supposed to form a list from list, taking into a new list only these numbers that are in a certain range. The predicate works, but suppose that I want to get a list not including bounds.
So I change the condition A >= L, A =< R to A > L, A < R, but then I only get "True", and Prolog outputs nothing.
What could be a problem here?
My code is:
range([], _, _, []).
range([A|L1], L, R, [A|L2]) :-
A>L,
A<R,
range(L1, L, R, L2).
range([A|L1], L, R, L2) :-
A=<L;
A>=R,
range(L1, L, R, L2).
This is what program outputs:
range([1,2,3,4,5], 1,4, X).
?- range([1,2,3,4,5,6,7,8,9,10], 1,3, X).
true .
This is what I want it to output:
?- range([1,2,3,4,5,6,7,8], 1, 5, X).
X = [2,3,4] .
I think you forgot needed parenthesis
range([A|L1], L, R, L2) :-
( A=<L ; A>=R ),
range(L1, L, R, L2).
otherwise, when A=<L, you loose the recursive call, and then variables remain not instantiated.
Priority of the conjunction and disjuntion, , and ;, makes it necessary to write the third clause as:
range([A|L1], L, R, L2) :-
( A=<L
; A>=R
),
range(L1, L, R, L2).

Prolog not returning asked value

I have this program in Prolog, it removes elements at each nth element from a list, like:
removenth([1,2,3,4,5,6], 2, R).
it should return : R = [1,3,5].
I have this:
removeallNth(F, N, R):- removeallNth(F, N, 1, R).
removeallNth([], _, _, R).
removeallNth([H|T], N, C, R):- N \== C, Nc is C + 1, concat(R,H,S),
removeallNth(T, N, Nc, S).
removeallNth([_|T], N, C, R):- N == C, removeallNth(T, N, 1, R).
The problem is that it returns true instead of R = [1,3,5]. I checked in SWI-Prolog debugger and it arrives to the correct result but then it keeps checking stuff. I understand it has to do with unification but I don't know how to apply it.
Consider this modification to your program:
removeallNth(F, N, R):- removeallNth(F, N, 1, R).
removeallNth([], _, _, []).
removeallNth([H|T], N, C, [H|R]):-
N \== C, Nc is C + 1,
removeallNth(T, N, Nc, R).
removeallNth([_|T], N, C, R):-
N == C,
removeallNth(T, N, 1, R).
In the first clause of removeallNth/4 you have to return an empty list.
In the second clause of removeallNth/4 you don't need to do the concat, you just have to return add the item in the list returned in the 4th argument of the head of that clause.

How to make my relation work

I have the following relation: index(X,N,List).
for example:
index(X,2,[a,b,c]).
X=b
index(b,N,[a,b,c]).
N=2
I don't know how to make my relation to work with the second example. It says that N is not defined well
Here is my code (it works well for the first example).
index(X,1,[X|_]).
index(X,N,[_|Tail]) :- N > 1, N1 is N - 1 , index(X,N1,Tail).
There is a SWI-Prolog built-in nth1/3 that does what you want:
?- nth1(N, [a, b, c], b).
N = 2 ;
false.
Look at its source code:
?- listing(nth1).
lists:nth1(A, C, D) :-
integer(A), !,
B is A+ -1,
nth0_det(B, C, D).
lists:nth1(A, B, C) :-
var(A), !,
nth_gen(B, C, 1, A).
true.
?- listing(nth0_det).
lists:nth0_det(0, [A|_], A) :- !.
lists:nth0_det(1, [_, A|_], A) :- !.
lists:nth0_det(2, [_, _, A|_], A) :- !.
lists:nth0_det(3, [_, _, _, A|_], A) :- !.
lists:nth0_det(4, [_, _, _, _, A|_], A) :- !.
lists:nth0_det(5, [_, _, _, _, _, A|_], A) :- !.
lists:nth0_det(A, [_, _, _, _, _, _|C], D) :-
B is A+ -6,
B>=0,
nth0_det(B, C, D).
true.
?- listing(nth_gen).
lists:nth_gen([A|_], A, B, B).
lists:nth_gen([_|B], C, A, E) :-
succ(A, D),
nth_gen(B, C, D, E).
true.
The variable N has not been instantiated to a numeric type when Prolog attempts to evaluate the goals N > 1 and N1 is N - 1 in the recursive clause defining index/3. This causes the instantiation error you are reporting.
I don't know how to solve your problem directly, but I have two suggestions. The first is to use an accumulator, so that the arithmetic operations in the recursive clause can be evaluated:
get(M,Xs,X) :- get(1,M,Xs,X).
get(N,N,[X|_],X).
get(N,M,[_|Xs],X) :-
L is N + 1,
get(L,M,Xs,X).
For instance:
?- index(N,[a,b],X).
N = 1,
X = a ;
N = 2,
X = b ;
false.
The other is to use a natural number type, so that the index can be constructed via unification:
nat(0).
nat(s(N)) :- nat(N).
get(s(0),[X|_],X).
get(s(N),[_|Y],X) :- get(N,Y,X).
For instance,
?- get(N,[a,b],X).
N = s(0),
X = a ;
N = s(s(0)),
X = b ;
false.
Hopefully this was helpful. Perhaps someone more knowledgeable will come along and give a better solution.

Resources