Issue in Prolog Programming - prolog

Hello I am new in Prolog and trying to write small program in Prolog in order to learn it....
I have written a program to remove the positional element mean remove(List,2,Ans) will remove all the elements of position 2,4,6,8.... from the list... below is my logic
remove(L,N,Ans):-
length(L,LEN),
T1 is 1 mod N,
add(L,N,[],LEN,T1,Res).
add(L,N,Ans,0,T,Ans).
add([H|T],N,Ans,LEN,0,Res):-
LEN1 is LEN-1,
T1 is 1 mod N,
add(T,N,Ans,LEN1,T1,Res).
add([H|T],N,Ans,LEN,T,Res):-
T =\= 0, LEN =\= 0,
LEN1 is LEN-1,
T1 is T1+1,
T2 is T1 mod N,
append([H],Ans,Result),
add(T,N,Result,LEN1,T2,Res).
but every time I run it is failing when finding add. below is the trace of the program that is have for a particular instance
[trace] ?- remove([1,2,3,4,5,6,7,8],2,X).
Call: (6) remove([1, 2, 3, 4, 5, 6, 7, 8], 2, _G2941) ? creep
Call: (7) length([1, 2, 3, 4, 5, 6, 7, 8], _G3039) ? creep
Exit: (7) length([1, 2, 3, 4, 5, 6, 7, 8], 8) ? creep
Call: (7) _G3041 is 1 mod 2 ? creep
Exit: (7) 1 is 1 mod 2 ? creep
Call: (7) add([1, 2, 3, 4, 5, 6, 7, 8], 2, [], 8, 1, _G3046) ? creep
Fail: (7) add([1, 2, 3, 4, 5, 6, 7, 8], 2, [], 8, 1, _G3046) ? creep
Fail: (6) remove([1, 2, 3, 4, 5, 6, 7, 8], 2, _G2941) ? creep
false.
Does anyone know where the problem is?

Hope you can find your way in your code. I think the better way to learn a language is actually debugging it... lurker' comment already put you on the right track. But I want to show how using builtins can change your perspective (this is of course true for any language, not just Prolog).
remove(L,N,Ans) :- findall(E, (nth1(I,L,E), I mod N =\= 0), Ans).
?- remove([1,2,3,4,5,6,7,8],2,X).
X = [1, 3, 5, 7].
edit when you
Call: (7) add([1, 2, 3, 4, 5, 6, 7, 8], 2, [], 8, 1, _G3046) ? creep
no rule can be matched, specifically T cannot be a list and the number 1
add([H|T],N,Ans,LEN,T,Res):-
that said, I'm not sure how you should correct the code...

A common prolog idiom is the use of a "helper" predicate that actually does the work and carries
one or more additional arguments that maintain state. In this case, we need a counter to track
our position within the source list.
remove( Xs , N , Ys ) :-
remove( Xs , 1 , N , Ys ). % Note the additional argument (our counter) initialized to 1
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , [X|Ys] ) :- % otherwise,
P mod N =\= 0 , % - if the current position is NOT a multiple of N,
P1 is P+1 , % - we increment the position,
remove(Xs,P1,N,Ys) % - and recurse down, adding the head of the list
. % to the result.
remove( [_|Xs] , P , N , Ys ) :- % otherwise,
P mod N =:= 0 , % - if the current position is a multiple of N,
P1 is P1+1 , % - increment the position,
remove(Xs,P1,N1,Ys) % - and recurse down, discarding the head of the list
. % Easy!
You might note some repetitive code. In the spirit of keeping things DRY, we can refactor it thusly:
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , Ys ) :- % otherwise,
keep_or_discard(X,P,N,Ys,Y1) , % - decided whether to keep or discard the current list head
P1 is P+1 , % - increment the counter
remove( Xs , P1 , N , Y1 ) % - and recurse down.
.
keep_or_discard( _ , P , N , Ys , Ys ) :- % if P is a multiple of N
P mod N =:= 0 , % - discard X,
! . % - and eliminate the choice point.
keep_or_discard( X , _ , _ , Ys , [X|Ys] ) . % otherwise, we keep it.
Some folk dislike the use of the cut to explicitly eliminate choice points, so alternatively, we can do the refactoring via the use of prolog's implication/if-then-else operator:
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , Ys ) :- % otherwise,
( P mod N =:= 0 % - if P is a multiple of N,
-> Y1 = Ys % - then we discard the list head
; [X|Y1] = Ys % - otherwise, we add it to the result list
) , % - and then ...
P1 is P+1 , % - increment the counter
remove( Xs , P1 , N , Y1 ) % - and recurse down.
.
Whether either of these refactorings is clearer, or easier to understand than the original is, of course, a personal choice.

Related

What is the simple way to find the max length of a list in prolog?

I'm new to learn the Prolog, I have a list, which looks like -> [[6, 7, 8,9], [6, 7, 8, 9], [6, 7, 8, 9], [7, 8, 9], [7, 8, 9],[5,6,7]], I want to find the all max length lists in the list, In this case, it should return [[6,7,8,9],[6,7,8,9],[6,7,8,9]]
my code
maxlist([A],A).
maxlist([A,B|Rest],Max):-
maxlist([B|Rest],Maxrest),
max(A,Maxrest,Max).
max(A,B,A):-
length(A,N1),
length(B,N2),
N1>N2.
max(A,B,B):-
length(A,N1),
length(B,N2),
N2>N1.
I could only find the one, I don't know how I find all, please don’t solve this predicate in complicate way or use complicates functor, it’s hard to understand for me.
Another possible solution is:
maxlist(ListOfLists, Answer) :-
maxlist(ListOfLists, -inf, [], Answer).
maxlist([], _, Answer, Answer).
maxlist([List|Lists], Max, Acc, Answer) :-
length(List, N),
( N = Max -> maxlist(Lists, Max, [List|Acc], Answer)
; N > Max -> maxlist(Lists, N, [List], Answer)
; maxlist(Lists, Max, Acc, Answer) ).
Examples:
?- maxlist([[6,7,8,9], [6,7,8,9], [6,7,8,9], [7,8,9], [7,8,9], [5,6,7]], M).
M = [[6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 9]].
?- maxlist([[1,2,3],[4,5,6,7,8,9],[0]], M).
M = [[4, 5, 6, 7, 8, 9]].
?- maxlist([[1,2,3], [4,5,6,7], [8], [9,0,1], [2,3,4,5]], M).
M = [[2, 3, 4, 5], [4, 5, 6, 7]].
The big issue with this problem is the repeated iteration of the list and its sublists, is it not?
I would start with a predicate that iterates over your list-of-lists once, prefixing each sublist with its length, and computing the length of the sublist as it goes:
map_lengths( Xs, L, X1 ) :- map_lengths(Xs,0,L,X1) .
map_lengths( [] , M , M , [] ) .
map_lengths( [X|Xs] , T , M , [L:X|Ys] ) :-
length(X,L),
T1 is max(L,T),
map_lengths(Xs,T1,M,Ys)
.
That's one pass over the list and its sublists.
Now that we have that, all we need is a way to extract sublists of a specified length. That's as easy as this:
lists_of_length( _ , [] , [] ) .
lists_of_length( L , [L:X|Xs] , [X|Ys] ) :- !, lists_of_length(L,Xs,Ys) .
lists_of_length( L , [_:_|Xs] , Ys ) :- lists_of_length(L,Xs,Ys) .
That is another single pass of the outer list. We no longer need to iterate over the sublists themselves.
And then, we just wire up the two predicates:
longest( Xs , Ys ) :-
map_lengths( Xs, L, X1 ) ,
lists_of_length(L,X1,Ys)
.
Putting it all together, you get:
https://swish.swi-prolog.org/p/VyUrjJjD.pl
longest( Xs , Ys ) :-
map_lengths( Xs, L, X1 ) ,
lists_of_length(L,X1,Ys)
.
map_lengths( Xs, L, X1 ) :- map_lengths(Xs,0,L,X1) .
map_lengths( [] , M , M , [] ) .
map_lengths( [X|Xs] , T , M , [L:X|Ys] ) :-
length(X,L),
T1 is max(L,T),
map_lengths(Xs,T1,M,Ys)
.
lists_of_length( _ , [] , [] ) .
lists_of_length( L , [L:X|Xs] , [X|Ys] ) :- !, lists_of_length(L,Xs,Ys) .
lists_of_length( L , [_:_|Xs] , Ys ) :- lists_of_length(L,Xs,Ys) .
Overall time and space complexity is O(N).
You can do it traversing the list once and keeping the current maximum length found along with the lists that have that maximum length:
maxlist(L, ML):-
maxlist(L, 0-[], ML).
maxlist([], _-ML, ML).
maxlist([A|L], MaxLen-ML, ML2):-
length(A, Len),
compare(C, Len, MaxLen),
memberchk(C-MaxLen1/ML1, [(<)-MaxLen/ML, (=)-MaxLen/[A|ML], _-Len/[A]]),
maxlist(L, MaxLen1-ML1, ML2).
Sample run:
?- maxlist([[6, 7, 8,9], [6, 7, 8, 9], [6, 7, 8, 9], [7, 8, 9], [7, 8, 9],[5,6,7], [1,2,3,4,5]], ML).
ML = [[1, 2, 3, 4, 5]].
Another alternative:
max_len_lists(LstLists, LstMaxLenFilter) :-
max_len_lists_(LstLists, _LenMax, LstMaxLenFilter),
% No need to check for alternatives
!.
max_len_lists_([], 0, []).
max_len_lists_([H|T], Len, LstMax) :-
length(H, LenH),
% Use recursion to check the rest of the list
max_len_lists_(T, LenT, F),
( LenH = LenT -> Len = LenH, LstMax = [H|F]
; LenH > LenT -> Len = LenH, LstMax = [H]
; Len = LenT, LstMax = F ).

Turn List into number, increment the number, and then turn the number into a list

I have my head stuck in this exercise in prolog, I ve been trying to do it on my own but it just won't work. Example: ?-succesor([1,9,9],X) -> X = [2,0,0]. Had tried first to reverse the list and increment it with 1 and then do a if %10 = 0 the next element should be incremented too. Thing is that I m too used with programming syntax and I can't get my head wrapped around this.Any help would be appreciated.
I have done this so far, but the output is false.
%[1,9,9] -> 199 +1 -> 200;
numbers_atoms([],[]).
numbers_atoms([X|Y],[C|K]) :-
atom_number(C, X),
numbers_atoms(Y,K).
%([1,2,3],X)
digits_number(Digits, Number) :-
numbers_atoms(Digits, Atoms),
number_codes(Number, Atoms).
number_tolist( 0, [] ).
number_tolist(N,[A|As]) :-
N1 is floor(N/10),
A is N mod 10,
number_tolist(N1, As).
addOne([X],[Y]):-
digits_number(X,Y1), %[1,9,9] -> 199
Y1 is Y1+1, % 199 -> 200
number_tolist(Y1,[Y]), % 200 -> [2,0,0]
!.
You can solve this problem similarly to how you would solve it manually: traverse the list of digits until you reach the rightmost digit; increment that digit and compute the carry-on digit, which must be recursively propagated to the left. At the end, prepend the carry-on digit if it is equal to 1 (otherwise, ignore it).
% successor(+Input, -Output)
successor([X0|Xs], L) :-
successor(Xs, X0, C, Ys),
( C = 1 % carry-on
-> L = [C|Ys]
; L = Ys ).
% helper predicate
successor([], X, C, [Y]) :-
Z is X + 1,
Y is Z mod 10,
C is Z div 10. % carry-on
successor([X1|Xs], X0, C, [Y|Ys]) :-
successor(Xs, X1, C0, Ys),
Z is X0 + C0,
Y is Z mod 10,
C is Z div 10. % carry-on
Examples:
?- successor([1,9,9], A).
A = [2, 0, 0].
?- successor([2,7],A), successor(A,B), successor(B,C), successor(C,D).
A = [2, 8],
B = [2, 9],
C = [3, 0],
D = [3, 1].
?- successor([7,9,9,8], A), successor(A, B).
A = [7, 9, 9, 9],
B = [8, 0, 0, 0].
?- successor([9,9,9,9], A), successor(A, B).
A = [1, 0, 0, 0, 0],
B = [1, 0, 0, 0, 1].
Here's a version which doesn't use is and can work both ways:
successor(ListIn, ListOut) :-
reverse(ListIn, ListInRev),
ripple_inc(ListInRev, ListOutRev),
reverse(ListOutRev, ListOut).
ripple_inc([], [1]).
ripple_inc([0|T], [1|T]).
ripple_inc([1|T], [2|T]).
ripple_inc([2|T], [3|T]).
ripple_inc([3|T], [4|T]).
ripple_inc([4|T], [5|T]).
ripple_inc([5|T], [6|T]).
ripple_inc([6|T], [7|T]).
ripple_inc([7|T], [8|T]).
ripple_inc([8|T], [9|T]).
ripple_inc([9|T], [0|Tnext]) :-
ripple_inc(T, Tnext).
e.g.
?- successor([1,9,9], X).
X = [2, 0, 0]
?- successor([1,9,9], [2,0,0]).
true
?- successor(X, [2,0,0]).
X = [1, 9, 9]
although it's nicely deterministic when run 'forwards', it's annoying that if run 'backwards' it finds an answer, then leaves a choicepoint and then infinite loops if that choicepoint is retried. I think what causes that is starting from the higher number then reverse(ListIn, ListInRev) has nothing to work on and starts generating longer and longer lists both filled with empty variables and never ends.
I can constrain the input and output to be same_length/2 but I can't think of a way to constrain them to be the same length or ListOut is one item longer ([9,9,9] -> [1,0,0,0]).
This answer tries to improve the previous answer by #TessellatingHacker, like so:
successor(ListIn, ListOut) :-
no_longer_than(ListIn, ListOut), % weaker than same_length/2
reverse(ListIn, ListInRev),
ripple_inc(ListInRev, ListOutRev),
reverse(ListOutRev, ListOut).
The definition of no_longer_than/2 follows. Note the similarity to same_length/2:
no_longer_than([],_). % same_length([],[]).
no_longer_than([_|Xs],[_|Ys]) :- % same_length([_|Xs],[_|Ys]) :-
no_longer_than(Xs,Ys). % same_length(Xs,Ys).
The following sample queries still succeed deterministically, as they did before:
?- successor([1,9,9], X).
X = [2,0,0].
?- successor([1,9,9], [2,0,0]).
true.
The "run backwards" use of successor/2 now also terminates universally:
?- successor(X, [2,0,0]).
X = [1,9,9]
; false.

How to write a prolog program to print between a given range?

How can I write a a program in prolog to print even and odd numbers between a range?
Sample output:
Enter first number:2
Enter Second number:15
Even numbers:
2
4
6
8
10
12
14
Odd numbers:
1
3
5
7
9
11
13
15
Here's one way to do it:
odds_and_evens( H , H , [H] , [] ) :- % if lo and hi have converged,
0 =\= H rem 2 % and it's odd
. % then park it with the odds and succeed.
odds_and_evens( H , H , [] , [H] ) :- % if lo and hi have conveged,
0 =:= H rem 2 % and it's even
. % then park it with the evens and succeed.
odds_and_evens( L , H, [L|Odds] , Evens ) :- % else... park lo with the odds
L < H, % - if lo is less than hi
0 =\= L rem 2, % - and lo is odd
L1 is L+1, % - increment lo
odds_and_evens(L1, H, Odds, Evens ) % - and recurse down
. %
odds_and_evens( L , H, Odds , [H|Evens] ) :- % else... park lo with the evens
L < H, % - if lo is less than hi
0 =:= L rem 2, % - and lo is even
L1 is L+1, % - incement lo
odds_and_evens(L1, H, Odds, Evens ) % - and recurse down
. % Easy!
But... Prolog has an in-built between/3 that generates a range of integers. And findall/3 finds all the solutions to a query as a list. So one could also — and more succinctly and declaratively! — say:
odds_and_evens( L , H , Odds , Evens ) :-
findall( X , odds( L , H , X ) , Odds ),
findall( X , evens( L , H , X ) , Evens )
.
odds( L , H , N ) :- between(L,H,N), 0 =\= N rem 2 .
evens( L , H , N ) :- between(L,H,N), 0 =:= N rem 2 .
Once you have odds_and_evens/4 defined, you can than do this:
print_odds_and_evens( Lo, Hi ) :-
odds_and_evens(Lo,Hi,Odds,Evens),
write_to_console('Odd Numbers', Odds ),
write_to_console('Even Numbers', Evens )
.
write_to_console(Label, Ns ) :-
write(Label), writeln(':'),
write_to_console(Ns)
,
write_to_console([]) .
write_to_console([N|Ns]) :- writeln(N), write_to_console(Ns).
If that's too much recursion for you, you could also say (cribbing odds/3 and evens/3 from above):
print_odds_and_evens(Lo,Hi) :-
writeln('Odd Numbers:'),
odd(Lo,Hi,N),
writeln(N),
fail
.
print_odds_and_evens(Lo,Hi) :-
writeln('Even Numbers:'),
even(Lo,Hi,N),
writeln(N),
fail
.
print_odds_and_evens(_,_).
odd( L , H , N ) :- between(L,H,N), 0 =\= N rem 2 .
even( L , H , N ) :- between(L,H,N), 0 =:= N rem 2 .
Here is an answer based on SWI-Prolog partition/4.
example_1(Odd,Even) :-
numlist(1,15,List),
partition(is_even,List,Even,Odd).
is_even(N) :-
0 is N mod 2.
Example run
?- example_1(Odd,Even).
Odd = [1, 3, 5, 7, 9, 11, 13, 15],
Even = [2, 4, 6, 8, 10, 12, 14].
Here is a variation that puts the support predicate into a Lambda.
example_2(Odd,Even) :-
numlist(1,15,List),
partition([N]>>(0 is N mod 2),List,Even,Odd).
Example run
?- example_2(Odd,Even).
Odd = [1, 3, 5, 7, 9, 11, 13, 15],
Even = [2, 4, 6, 8, 10, 12, 14].
For answers to the other part of your multi-part question about entering the starting and ending values I would suggest using read_string/5.
See:
How to get user console input into a Prolog list (Answer)
Prolog: How to read data from console and store into database. (Answer)
Other Answers
Here is a solution that only uses Prolog ISO standard built-in predicates. It's also a fast solution as it avoid meta-predicates and appending lists:
print_even_odd(Lower, Upper) :-
even_odd(Lower, Upper, Even, Odd),
write('Even: '), write(Even), nl,
write('Odd: '), write(Odd), nl.
even_odd(Lower, Upper, Even, Odd) :-
Lower =< Upper,
( Lower mod 2 =:= 0 ->
even_odd_lists(Lower, Upper, Even, Odd)
; even_odd_lists(Lower, Upper, Odd, Even)
).
even_odd_lists(Upper, Upper, [Upper], []) :-
!.
even_odd_lists(N, Upper, [N| Even], Odd) :-
M is N + 1,
even_odd_lists(M, Upper, Odd, Even).
Sample calls:
| ?- print_even_odd(1, 24).
Even: [2,4,6,8,10,12,14,16,18,20,22,24]
Odd: [1,3,5,7,9,11,13,15,17,19,21,23]
yes
| ?- print_even_odd(2, 24).
Even: [2,4,6,8,10,12,14,16,18,20,22,24]
Odd: [3,5,7,9,11,13,15,17,19,21,23]
yes
| ?- print_even_odd(1, 35).
Even: [2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34]
Odd: [1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35]
yes
There are several possible solutions. Here a, naive, without using higher order predicates:
print_even_odd(Lower,Upper,[],[]):-
Lower > Upper, !.
print_even_odd(Lower,Upper,Lodd,Leven):-
Res is Lower mod 2,
( Res =:= 0 ->
Leven = [Lower | LE1], LO1 = Lodd ;
Lodd = [Lower | LO1], LE1 = Leven
),
L1 is Lower + 1,
print_even_odd(L1,Upper,LO1,LE1).
?- print_even_odd(1,15,LE,LO).
LE = [1, 3, 5, 7, 9, 11, 13, 15],
LO = [2, 4, 6, 8, 10, 12, 14]
You can write more compact solutions using higher order predicates as sugggested in the comments.
Here is another possible solution:
% range(+Start, +Stop, +Step, -List)
range(Start, Stop, Step, List) :-
( Start > Stop
-> List = []
; List = [Start|Rest],
Next is Start + Step,
range(Next, Stop, Step, Rest) ).
% even_odd_lists(+Lower, +Upper, -EList, -OList)
even_odd_lists(Lower, Upper, EList, OList) :-
FirstEven is Lower + Lower mod 2,
FirstOdd is Lower + (Lower-1) mod 2,
range(FirstEven, Upper, 2, EList),
range(FirstOdd, Upper, 2, OList).
Some sample queries are:
?- range(1, 10, 3, R).
R = [1, 4, 7, 10].
?- range(1, 10, 2, R).
R = [1, 3, 5, 7, 9].
?- range(2, 10, 2, R).
R = [2, 4, 6, 8, 10].
?- even_odd_lists(1, 15, LE, LO).
LE = [2, 4, 6, 8, 10, 12, 14],
LO = [1, 3, 5, 7, 9, 11, 13, 15].
?- even_odd_lists(2, 15, LE, LO).
LE = [2, 4, 6, 8, 10, 12, 14],
LO = [3, 5, 7, 9, 11, 13, 15].

Calculate whether the sum of exactly three values in a list is equal to N

Examples: ([1,2,3,7,6,9], 6). should print True, as 1+2+3=6.
([1,2,3,7,6,9], 5). should print False as there are no three numbers whose sum is 5.
([],N) where N is equal to anything should be false.
Need to use only these constructs:
A single clause must be defined (no more than one clause is allowed).
Only the following is permitted:
+, ,, ;, ., !, :-, is, Lists -- Head and Tail syntax for list types, Variables.
I have done a basic coding as per my understanding.
findVal([Q|X],A) :-
[W|X1]=X,
[Y|X2]=X,
% Trying to append the values.
append([Q],X1,X2),
% finding sum.
RES is Q+W+Y,
% verify here.
(not(RES=A)->
% finding the values.
(findVal(X2,A=)->
true
;
(findVal(X,A)->
% return result.
true
;
% return value.
false))
;
% return result.
true
).
It does not seem to run throwing the following error.
ERROR:
Undefined procedure: findVal/2 (DWIM could not correct goal)
Can someone help with this?
You can make use of append/3 [swi-doc] here to pick an element from a list, and get access to the rest of the elements (the elements after that element). By applying this technique three times, we thus obtain three items from the list. We can then match the sum of these elements:
sublist(L1, S) :-
append(_, [S1|L2], L1),
append(_, [S2|L3], L2),
append(_, [S3|_], L3),
S is S1 + S2 + S3.
Well, you can iterate (via backtracking) over all the sublists of 3 elements from the input list and see which ones sum 3:
sublist([], []).
sublist([H|T], [H|S]) :- sublist(T, S).
sublist([_|T], S) :- sublist(T, S).
:- length(L, 3), sublist([1,2,3,7,6,9], L), sum_list(L, 6).
I'm giving a partial solution here because it is an interesting problem even though the constraints are ridiculous.
First, I want something like select/3, except that will give me the tail of the list rather than the list without the item:
select_from(X, [X|R], R).
select_from(X, [_|T], R) :- select_from(X, T, R).
I want the tail, rather than just member/2, so I can recursively ask for items from the list without getting duplicates.
?- select_from(X, [1,2,3,4,5], R).
X = 1,
R = [2, 3, 4, 5] ;
X = 2,
R = [3, 4, 5] ;
X = 3,
R = [4, 5] ;
X = 4,
R = [5] ;
X = 5,
R = [] ;
false.
Yeah, this is good. Now I want to build a thing to give me N elements from a list. Again, I want combinations, because I don't want unnecessary duplicates if I can avoid it:
select_n_from(1, L, [X]) :- select_from(X, L, _).
select_n_from(N, L, [X|R]) :-
N > 1,
succ(N0, N),
select_from(X, L, Next),
select_n_from(N0, Next, R).
So the idea here is simple. If N = 1, then just do select_from/3 and give me a singleton list. If N > 1, then get one item using select_from/3 and then recur with N-1. This should give me all the possible combinations of items from this list, without giving me a bunch of repetitions I don't care about because addition is commutative and associative:
?- select_n_from(3, [1,2,3,4,5], R).
R = [1, 2, 3] ;
R = [1, 2, 4] ;
R = [1, 2, 5] ;
R = [1, 3, 4] ;
R = [1, 3, 5] ;
R = [1, 4, 5] ;
R = [2, 3, 4] ;
R = [2, 3, 5] ;
R = [2, 4, 5] ;
R = [3, 4, 5] ;
false.
We're basically one step away now from the result, which is this:
sublist(List, N) :-
select_n_from(3, List, R),
sumlist(R, N).
I'm hardcoding 3 here because of your problem, but I wanted a general solution. Using it:
?- sublist([1,2,3,4,5], N).
N = 6 ;
N = 7 ;
N = 8 ;
N = 8 ;
N = 9 ;
N = 10 ;
N = 9 ;
N = 10 ;
N = 11 ;
N = 12 ;
false.
You can also check:
?- sublist([1,2,3,4,5], 6).
true ;
false.
?- sublist([1,2,3,4,5], 5).
false.
?- sublist([1,2,3,4,5], 8).
true ;
true ;
false.
New users of Prolog will be annoyed that you get multiple answers here, but knowing that there are multiple ways to get 8 is probably interesting.

determining if there are equal number of a and b terms in a List using prolog

The problem states: Define a relation, equal_a_b(L), in Prolog, where equal_a_b(L) is true if L contains an equal number of a and b terms.
I wrote code to count the number of a terms and b terms and check to see if a==b. If a===b is false then the program should output no. However, when i test my code, it outputs yes and i dont know why.
Here's the code:
equal_a_b(L):-
eqab(L, A, B),
eqabn(A, B).
eqab([], 0, 0).
eqab([a|L], X, Y):- eqab(L, Z, A), X is Z + 1, Y is A + 0.
eqab([b|L], X, Y):- eqab(L, Z, A), X is Z + 0, Y is A + 1.
eqab([C|L], X, Y):- eqab(L, Z, A), X is Z + 0, Y is A + 0.
eqabn(A, B):- A==B.
Heres the trace program for example (equal_a_b([a]). which should output no:
| ?- trace, equal_a_b([a]).
The debugger will first creep -- showing everything (trace)
1 1 Call: equal_a_b([a]) ?
2 2 Call: eqab([a],_85,_86) ?
3 3 Call: eqab([],_110,_111) ?
3 3 Exit: eqab([],0,0) ?
4 3 Call: _138 is 0+1 ?
4 3 Exit: 1 is 0+1 ?
5 3 Call: _166 is 0+0 ?
5 3 Exit: 0 is 0+0 ?
2 2 Exit: eqab([a],1,0) ?
6 2 Call: eqabn(1,0) ?
7 3 Call: 1==0 ?
7 3 Fail: 1==0 ?
6 2 Fail: eqabn(1,0) ?
2 2 Redo: eqab([a],1,0) ? n
(10 ms) yes
Any help is appreciated, Thanks.
equal_a_b(Xs) :-
equals_a_b__n(Xs, 0).
equals_a_b__n([], 0).
equals_a_b__n([C|Cs], N0) :-
char_n_(C, N0,N1),
equals_a_b__n(Cs, N1).
char_n_(C, N, N) :-
dif(C,a),
dif(C,b).
char_n_(a, N0, N) :-
N is N0 + 1.
char_n_(b, N0, N) :-
N is N0 - 1.
This solution is a true relation, you can even ask
Tell me all lists that contain the same number of characters a and b.
?- length(Xs, N), equal_a_b(Xs).
Xs = [], N = 0
; Xs = [_A], N = 1,
dif(_A,a), dif(_A,b)
; Xs = [_A,_B], N = 2,
dif(_A,a), dif(_A,b), dif(_B,a), dif(_B,b)
; Xs = [a,b], N = 2
; Xs = [b,a], N = 2
; Xs = [_A,_B,_C], N = 3,
dif(_A,a), dif(_A,b), dif(_B,a), dif(_B,b), dif(_C,a), dif(_C,b)
; Xs = [_A,a,b], N = 3,
dif(_A,a), dif(_A,b)
; Xs = [_A,b,a], N = 3,
dif(_A,a), dif(_A,b)
; Xs = [a,_A,b], N = 3,
dif(_A,a), dif(_A,b)
; Xs = [a,b,_A], N = 3,
dif(_A,a), dif(_A,b)
; Xs = [b,_A,a], N = 3,
dif(_A,a), dif(_A,b)
; Xs = [b,a,_A], N = 3,
dif(_A,a), dif(_A,b)
; ... .
And then, it is also more efficient in current implementations. In fact, in the case of a ground list Xs with length l, it only requires space proportional to log l, whereas your and #lurker 's solution require space that is proportional to l.
as lurker noted, your program must avoid the 'catchall' rule when it 'sees' an 'a' or a 'b'. The simpler patch I can think of: commit the choices with cuts. Here is one:
...
eqab([a|L], X, Y):- eqab(L, Z, A), !, X is Z + 1, Y is A + 0.
...
but the whole would be simpler if you 'invert' the control flow: count down and check, when the list becomes empty, if counts match.

Resources