Related
SWI-Prolog has no list concatenation function, and I have to write it myself. I know the classic solution, but it does not allow access to the head and tail of the second list.
conc([], L, L).
conc([X|L1], L2, [X|L3]):-
conc(L1, L2, L3).
How can I add a program to ask questions to the compiler like this?
?- conc([_, _, _], [L | [_, _, _]], [a,b,c,d,e,f,g,h,i,j,k,l,m]).
I know that I can write the same thing in the form:
?- conc([_, _, _ | L], [_, _, _], [a,b,c,d,e,f,g,h,i,j,k,l,m]).
A query like
conc([_, _, _], [L | [_, _, _]], [a,b,c,d,e,f,g,h,i,j,k,l,m]).
does not make much sense, given you are looking for a list L. After all [L|[_,_,_]] is just equivalent to [L,_,_,_], although the latter is syntactical sugar.
If you are looking for a way to obtain the elements in front of the list, you can just use conc/3 a second time, like:
conc([_,_,_], B, [a,b,c,d,e,f,g,h,i,j,k,l,m]), conc(L, [_,_,_], B).
This gives us the expected result:
?- conc([_,_,_], B, [a,b,c,d,e,f,g,h,i,j,k,l,m]), conc(L, [_,_,_], B).
B = [d, e, f, g, h, i, j, k, l|...],
L = [d, e, f, g, h, i, j] ;
false.
We can make a conc/4 that splits the list in three parts, like:
conc(A, B, C, L) :-
conc(A, D, L),
conc(B, C, D).
and then query like:
?- conc([_,_,_], L, [_,_,_], [a,b,c,d,e,f,g,h,i,j,k,l,m]).
L = [d, e, f, g, h, i, j] ;
false.
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.
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).
While attempting to learn Prolog I came across a good exercise which was to write a program that displays the Nth Fibonacci number. After some work I got it working and then decided to see if I could write a program that displays a range of Fibonacci numbers according to the input.
For instance the input:
?- fib_sequence(2,5,Output).
Gives the output:
?- Output = [1,1,2,3]
I am having difficulty, however, in finding a good starting point. This is what I have so far:
fib(0, 0).
fib(1, 1).
fib(N, F) :- X is N - 1, Y is N - 2, fib(X, A), fib(Y, B), F is A + B.
fib_sequence(A,B,R) :- fib(A,Y) , fib(B,Z).
I know I must assign a value to R, but I'm not sure how to assign multiple values. Any help is greatly appreciated.
Observe that your fib_sequence cannot be done in a single predicate clause: you need at least two to keep things recursive - one to produce an empty list when A is greater than B (i.e. we've exhausted the range from A to B), and another one to prepend X from fib(A,X) to a list that you are building, increment A by 1, and call fib_sequence recursively to produce the rest of the sequence.
The first predicate clause would look like this:
fib_sequence(A,B,[]) :- A > B.
The second predicate clause is a bit harder:
fib_sequence(A,B,[H|T]) :-
A =< B /* Make sure A is less than or equal to B */
, fib(A, H) /* Produce the head value from fib(A,...) */
, AA is A + 1 /* Produce A+1 */
, fib_sequence(AA, B, T). /* Produce the rest of the list */
Prolog has some helper builtin to handle numeric sequences, then as an alternative to dasblinkenlight' answer, here is an idiomatic 'query':
fib_sequence(First, Last, Seq) :-
findall(F, (between(First,Last,N), fib(N,F)), Seq).
note that it will not work out-of-the-box with your fib/2, because there is a bug: I've added a condition that avoid the endless loop you would experience trying to backtrack on fib/2 solutions:
fib(N, F) :- N > 1, % added sanity check
X is N - 1, Y is N - 2, fib(X, A), fib(Y, B), F is A + B.
Here's yet another approach. First, I redid fib a little so that it only recursively calls itself once instead of twice. To do this, I created a predicate that returns the prior the last two Fibonacci values instead of the last one:
fib(N, F) :-
fib(N, F, _).
fib(N, F, F1) :-
N > 2,
N1 is N-1,
fib(N1, F1, F0),
F is F0 + F1.
fib(1, 1, 0).
fib(2, 1, 1).
For getting the sequence, I chose an algorithm with the Fibonacci calculation built-in so that it doesn't need to call fib O(n^2) times. It does, however, need to reverse the list when complete:
fib_sequence(A, B, FS) :-
fib_seq_(A, B, FSR),
reverse(FSR, FS).
fib_sequence_(A, B, []) :-
A > B.
fib_sequence_(A, B, [F]) :-
A =:= B,
fib(A, F, _).
fib_sequence_(A, B, [F1,F0]) :-
1 is B - A,
fib(B, F1, F0).
fib_sequence_(A, B, [F2,F1,F0|FT] ) :-
B > A,
B1 is B - 1,
fib_sequence_(A, B1, [F1,F0|FT]),
F2 is F1 + F0.
Here's one more way, to do it without the reverse, but the reverse method above still appears to be a little faster in execution.
fib_sequence_dl(A, B, F) :-
fib_sequence_dl_(A, B, F, [_,_|[]]).
fib_sequence_dl_(A, B, [], _) :-
A > B, !.
fib_sequence_dl_(A, B, [F], _) :-
A =:= B,
fib(A, F, _), !.
fib_sequence_dl_(A, B, [F0,F1|T], [F0,F1|T]) :-
1 is B - A,
fib(B, F1, F0), !.
fib_sequence_dl_(A, B, F, [F1,F2|T]) :-
A < B,
B1 is B - 1,
fib_sequence_dl_(A, B1, F, [F0,F1|[F2|T]]),
F2 is F0 + F1.
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.