Related
I'm new in prolog, and I wanted to create a "function" to count how many different values I have in a list.
I've made this predicate to count the total number of values:
tamanho([],0).
tamanho([H|T],X) :- tamanho(T,X1), X is X1+1.
I wanted to follow the same line of thought like in this last predicate.(Don't know if that's possible).
So in a case where my list is [1,2,2,3], the answer would be 3.
Can someone give me a little help?
Here is a pure version which generalizes the relation. You can not only count but just see how elements have to look like in order to obtain a desired count.
In SWI, you need to install reif first.
:- use_module(library(reif),[memberd_t/3]).
:- use_module(library(clpz)). % use clpfd in SWI instead
:- op(150, fx, #). % backwards compatibility for old SWI
nt_int(false, 1).
nt_int(true, 0).
list_uniqnr([],0).
list_uniqnr([E|Es],N0) :-
#N0 #>= 0,
memberd_t(E, Es, T),
nt_int(T, I),
#N0 #= #N1 + #I,
list_uniqnr(Es,N1).
tamanho(Xs, N) :-
list_uniqnr(Xs, N).
?- tamanho([1,2,3,1], Nr).
Nr = 3.
?- tamanho([1,2,X,1], 3).
dif:dif(X,1), dif:dif(X,2).
?- tamanho([1,2,X,Y], 3).
X = 1, dif:dif(Y,1), dif:dif(Y,2)
; Y = 1, dif:dif(X,1), dif:dif(X,2)
; X = 2, dif:dif(Y,1), dif:dif(Y,2)
; Y = 2, dif:dif(X,1), dif:dif(X,2)
; X = Y, dif:dif(X,1), dif:dif(X,2)
; false.
You can fix your code by adding 1 to the result that came from the recursive call if H exists in T, otherwise, the result for [H|T] call is the same result for T call.
tamanho([],0).
tamanho([H|T], X) :- tamanho(T, X1), (member(H, T) -> X is X1; X is X1 + 1).
Tests
/*
?- tamanho([], Count).
Count = 0.
?- tamanho([1,a,21,1], Count).
Count = 3.
?- tamanho([1,2,3,1], Count).
Count = 3.
?- tamanho([1,b,2,b], Count).
Count = 3.
*/
In case the input list is always numerical, you can follow #berbs's suggestion..
sort/2 succeeds if input list has non-numerical items[1] so you can use it without any restrictions on the input list, so tamanho/2 could be just like this
tamanho(T, X) :- sort(T, TSorted), length(TSorted, X).
[1] thanks to #Will Ness for pointing me to this.
I've been searching for something that might help me with my problem all over the internet but I haven't been able to make any progress. I'm new to logic programming and English is not my first language so apologize for any mistake.
Basically I want to implement this prolog program: discord/3 which has arguments L1, L2 lists and P where P are the indexes of the lists where L1[P] != L2[P] (in Java). In case of different lengths, the not paired indexes just fail. Mode is (+,+,-) nondet.
I got down the basic case but I can't seem to wrap my head around on how to define P in the recursive call.
discord(_X,[],_Y) :-
fail.
discord([H1|T1],[H1|T2],Y) :-
???
discord(T1,T2,Z).
discord([_|T1],[_|T2],Y) :-
???
discord(T1,T2,Z).
The two clauses above are what I came up to but I have no idea on how to represent Y - and Z - so that the function actually remembers the length of the original list. I've been thinking about using nth/3 with eventually an assert but I'm not sure where to place them in the program.
I'm sure there has to be an easier solution although. Thanks in advance!
You can approach this in two ways. First, the more declarative way would be to enumerate the indexed elements of both lists with nth1/3 and use dif/2 to ensure that the two elements are different:
?- L1 = [a,b,c,d],
L2 = [x,b,y,d],
dif(X, Y),
nth1(P, L1, X),
nth1(P, L2, Y).
X = a, Y = x, P = 1 ;
X = c, Y = y, P = 3 ;
false.
You could also attempt to go through both list at the same time and keep a counter:
discord(L1, L2, P) :-
discord(L1, L2, 1, P).
discord([X|_], [Y|_], P, P) :-
dif(X, Y).
discord([_|Xs], [_|Ys], N, P) :-
succ(N, N1),
discord(Xs, Ys, N1, P).
Then, from the top level:
?- discord([a,b,c,d], [a,x,c,y], Ps).
Ps = 2 ;
Ps = 4 ;
false.
I want to alter the following code so that genN(3,R) outputs:
R=0.
R=1.
R=2.
Instead of a list R=[0,1,2]. How would I go about completing this?
genN(0,[]).
genN(N,R) :-
N > 0,
N1 is N-1,
genN(N1,R1),
append(R1,[N1],R),
!.
Use genN/2 and member/2 in conjunction, like this:
?- genN(3,Rs), member(R,Rs).
Rs = [0,1,2], R = 0 ;
Rs = [0,1,2], R = 1 ;
Rs = [0,1,2], R = 2.
You can do :
gen(N, R) :-
gen_one(N, 0, R).
gen_one(N, V, R) :-
N > V,
( R = V; V1 is V+1, gen_one(N,V1,R)).
from0_upto(N, R) :-
succ(N0, N),
between(0, N0, R).
Consider that it is not trivial (not impossible either) to write your own version of between/3 that behaves well in all corner cases. There are several attempts at this here on Stackoverflow, as well as an implementation in Prolog here: http://www.cs.otago.ac.nz/staffpriv/ok/pllib.htm (search for the string "between/3".
The Bottom Line
If you need a list, generate a list. If you need solution upon backtracking, generate solutions upon backtracking.
I was just introduced to Prolog and am trying to write a predicate that finds the Max value of a list of integers. I need to write one that compares from the beginning and the other that compares from the end. So far, I have:
max2([],R).
max2([X|Xs], R):- X > R, max2(Xs, X).
max2([X|Xs], R):- X <= R, max2(Xs, R).
I realize that R hasn't been initiated yet, so it's unable to make the comparison. Do i need 3 arguments in order to complete this?
my_max([], R, R). %end
my_max([X|Xs], WK, R):- X > WK, my_max(Xs, X, R). %WK is Carry about
my_max([X|Xs], WK, R):- X =< WK, my_max(Xs, WK, R).
my_max([X|Xs], R):- my_max(Xs, X, R). %start
other way
%max of list
max_l([X],X) :- !, true.
%max_l([X],X). %unuse cut
%max_l([X],X):- false.
max_l([X|Xs], M):- max_l(Xs, M), M >= X.
max_l([X|Xs], X):- max_l(Xs, M), X > M.
Ignoring the homework constraints about starting from the beginning or the end, the proper way to implement a predicate that gets the numeric maximum is as follows:
list_max([P|T], O) :- list_max(T, P, O).
list_max([], P, P).
list_max([H|T], P, O) :-
( H > P
-> list_max(T, H, O)
; list_max(T, P, O)).
A very simple approach (which starts from the beginning) is the following:
maxlist([],0).
maxlist([Head|Tail],Max) :-
maxlist(Tail,TailMax),
Head > TailMax,
Max is Head.
maxlist([Head|Tail],Max) :-
maxlist(Tail,TailMax),
Head =< TailMax,
Max is TailMax.
As you said, you must have the variables instantiated if you want to evaluate an arithmetic expression. To solve this, first you have to make the recursive call, and then you compare.
Hope it helps!
As an alternative to BLUEPIXY' answer, SWI-Prolog has a builtin predicate, max_list/2, that does the search for you. You could also consider a slower method, IMO useful to gain familiarity with more builtins and nondeterminism (and then backtracking):
slow_max(L, Max) :-
select(Max, L, Rest), \+ (member(E, Rest), E > Max).
yields
2 ?- slow_max([1,2,3,4,5,6,10,7,8],X).
X = 10 ;
false.
3 ?- slow_max([1,2,10,3,4,5,6,10,7,8],X).
X = 10 ;
X = 10 ;
false.
edit
Note you don't strictly need three arguments, but just to have properly instantiated variables to carry out the comparison. Then you can 'reverse' the flow of values:
max2([R], R).
max2([X|Xs], R):- max2(Xs, T), (X > T -> R = X ; R = T).
again, this is slower than the three arguments loops, suggested in other answers, because it will defeat 'tail recursion optimization'. Also, it does just find one of the maxima:
2 ?- max2([1,2,3,10,5,10,6],X).
X = 10 ;
false.
Here's how to do it with lambda expressions and meta-predicate foldl/4, and, optionally, clpfd:
:- use_module([library(lambda),library(apply),library(clpfd)]).
numbers_max([Z|Zs],Max) :- foldl(\X^S^M^(M is max(X,S)),Zs,Z,Max).
fdvars_max( [Z|Zs],Max) :- foldl(\X^S^M^(M #= max(X,S)),Zs,Z,Max).
Let's run some queries!
?- numbers_max([1,4,2,3],M). % integers: all are distinct
M = 4. % succeeds deterministically
?- fdvars_max( [1,4,2,3],M).
M = 4. % succeeds deterministically
?- numbers_max([1,4,2,3,4],M). % integers: M occurs twice
M = 4. % succeeds deterministically
?- fdvars_max( [1,4,2,3,4],M).
M = 4. % succeeds deterministically
What if the list is empty?
?- numbers_max([],M).
false.
?- fdvars_max( [],M).
false.
At last, some queries showing differences between numbers_max/2 and fdvars_max/2:
?- numbers_max([1,2,3,10.0],M). % ints + float
M = 10.0.
?- fdvars_max( [1,2,3,10.0],M). % ints + float
ERROR: Domain error: `clpfd_expression' expected, found `10.0'
?- numbers_max([A,B,C],M). % more general use
ERROR: is/2: Arguments are not sufficiently instantiated
?- fdvars_max( [A,B,C],M).
M#>=_X, M#>=C, M#=max(C,_X), _X#>=A, _X#>=B, _X#=max(B,A). % residual goals
list_max([L|Ls], Max) :- foldl(num_num_max, Ls, L, Max).
num_num_max(X, Y, Max) :- Max is max(X, Y).
%Query will be
?-list_max([4,12,5,3,8,90,10,11],Max).
Max=90
Right now I was working with recursion in Prolog, so if it is useful for someone I will leave 'my two cents' solving it in the two ways that I have thought:
% Start
start :- max_trad([2, 4, 6, 0, 5], MaxNumber1),
max_tail([2, 4, 6, 0, 5], 0, MaxNumber2),
show_results(MaxNumber1, MaxNumber2).
% Traditional Recursion (Method 1)
max_trad([Head|Tail], Max) :- max_trad(Tail, Value), Head > Value, Max is Head.
max_trad([Head|Tail], Max) :- max_trad(Tail, Value), Head =< Value, Max is Value.
max_trad([], 0).
% Tail Recursion (Method 2)
max_tail([], PartialMax, PartialMax).
max_tail([Head|Tail], PartialMax, FinalMax) :- Head > PartialMax, max_tail(Tail, Head, FinalMax).
max_tail([_|Tail], PartialMax, FinalMax) :- max_tail(Tail, PartialMax, FinalMax).
% Show both of the results
show_results(MaxNumber1, MaxNumber2) :-
write("The max value (obtained with traditional recursion) is: "), writeln(MaxNumber1),
write("The max value (obtained with tail recursion) is: "), writeln(MaxNumber2).
The output of the above code is:
Both methods are similar, the difference is that in the second an auxiliary variable is used in the recursion to pass values forward, while in the first method, although we have one less variable, we are filling the Stack with instructions to be executed later, so if it were an exaggeratedly large list, the second method is appropriate.
maximum_no([],Max):-
write("Maximum No From the List is:: ",Max).
maximum_no([H|T],Max):-
H>Max,
N = H,
maximum_no(T,N).
maximum_no(L,Max):-
maximum_no(L,Max).
The maximum number in a list in Prolog ?
max([],A):-print(A),!.
max([Head | Tail] , A):-A =< Head ,A1 is Head , max(Tail,A1) ; max(Tail,A).
max(L,M):-
member(M,L),
findall(X,(member(X,L),X>M),NL),
length(NL,0).
Basically, I need to create a predicate of the form sublist(S,M,N,L), where S is a new list formed from the elements of L between index M and index N, inclusive.
Here's where I've gotten:
sublist([],_,_,[]).
sublist([],M,N,_) :- (M > N).
sublist(S,M,N,L) :- sublist2(S,M,N,L,-1).
sublist2([H|T],St,En,[H2|T2],Idx) :-
(Idx2 is Idx + 1,
St =< Idx2,
En >= Idx2,
H = H2,
sublist2(T,St,En,T2,Idx2);
Idx2 is Idx + 1,
sublist2(T,St,En,T2,Idx2)).
As with all my prolog problems, I feel I'm making it way more complicated than it should be. I've got the base cases right, but anything else evaluates to false. Any advice for this problem, and just general approach to prolog? I understand the language for the most part, but I can't seem to see the simple solutions.
Simple solutions follow simple outlook. For lists it's recursion. Recursive programming is simple - just imagine you already have your function, following the given interface/requirements, and so you get to use it whenever you feel like it (but better, in the reduced cases).
sublist(S,M,N,[_A|B]):- M>0, M<N, sublist(S,M-1,N-1,B).
think of it as stating a law of sublists: sublist in a shorter list starts at decreased index.
sublist(S,M,N,[A|B]):- 0 is M, M<N, N2 is N-1, S=[A|D], sublist(D,0,N2,B).
and,
sublist([],0,0,_).
it is exclusive in the second index. tweak it. :)
There is the possibility to handle indexing in a way similar to more traditional languages:
sublist(L, M, N, S) :-
findall(E, (nth1(I, L, E), I >= M, I =< N), S).
or equivalently
sublist(L, M, N, S) :-
findall(E, (between(M, N, I), nth1(I, L, E)), S).
nth1/3 is for indexing from 1, otherwise nth0/3 allows C style - start from 0. I've placed the sublist as last argument. It's a common convention in Prolog to place output parameters after input.
Here a (cumbersome) recursive definition
sublist(L,M,N,S) :- sublist2(1,L,M,N,S).
sublist2(_,[],_,_,[]).
sublist2(I,[X|Xs],M,N,[X|Ys]) :-
between(M,N,I),
J is I + 1,
!, sublist2(J,Xs,M,N,Ys).
sublist2(I,[_|Xs],M,N,Ys) :-
J is I + 1,
sublist2(J,Xs,M,N,Ys).