Related
I am a complete amateur on Prolog so my question might be very basic. I want to automatically generate a list from 1 to N, then split it into even and odd, from just one integer input (so I don't input the list manually). Let's say I input 5, then the result should be like this:
X = [1,3,5]
Y = [2,4]
Doesn't matter which one is X, which one is Y.
How should I tackle this problem?
I know the built-in function to generate list is numlist(1,5,L).
I also found an answer on how to split the list here
I tried to combine those two like this
separate_even_odd(N) :- numlist(1,N,L), separate_even_odd(L, X, Y).
Then call the function separate_even_odd(5).
All i got is True.
Ultimately I want to append the odd list to the even list but let's put that on another story. For now, I just want it splitted.
SWI-Prolog has a library predicate partition/4 that seems it's done to fulfill your needs:
separate_even_odd(Integers, Even, Odd) :-
partition(integer_is_even, Integers, Even, Odd).
integer_is_even(I) :- I mod 2 =:= 0.
Instead of providing the service predicate integer_is_even/1, we could as well use the lambda library(yall):
separate_even_odd(Integers, Even, Odd) :-
partition([I] >> (I mod 2 =:= 0), Integers, Even, Odd).
and we get
?- numlist(1,5,L), separate_even_odd(L, Even, Odd).
L = [1, 2, 3, 4, 5],
Even = [2, 4],
Odd = [1, 3,
Just to illustrate some of the unusual constructs of Prolog (unification and if/then/else), take a look at a simple implementation, in procedural style, without library predicates:
list_with_separate_even_odd(IntegerLow, IntegerHigh, Even, Odd) :-
( IntegerLow > IntegerHigh
-> Even = [], Odd = []
; ( IntegerLow mod 2 =:= 0
-> Even = [IntegerLow|RestEven], Odd = RestOdd
; Even = RestEven, Odd = [IntegerLow|RestOdd]
),
LowSucc is IntegerLow + 1,
list_with_separate_even_odd(LowSucc, IntegerHigh, RestEven, RestOdd)
).
Note in particular how =/2 performs unification, not assigment.
Alternative method, with an introduction to difference lists due to "Ultimately I want to append the odd list to the even list":
between_evens_odds(Upper, Evens, EvensTail, Odds) :-
integer(Upper),
Upper #>= 1,
between_evens_odds_(1, Upper, Evens, EvensTail, Odds).
between_evens_odds_(Upto, Upper, Evens, EvensTail, Odds) :-
compare(Comp, Upper, Upto),
between_evens_odds_comp_(Comp, Upto, Upper, Evens, EvensTail, Odds).
between_evens_odds_comp_(<, _Upto, _Upper, EvensTail, EvensTail, []).
% Started with 1, so final number will also be odd
between_evens_odds_comp_(=, Upto, _Upper, EvensTail, EvensTail, [Upto]).
between_evens_odds_comp_(>, Upto, Upper, [Upto1|Evens], EvensTail, [Upto|Odds]) :-
Upto1 is Upto + 1,
Upto2 is Upto + 2,
between_evens_odds_(Upto2, Upper, Evens, EvensTail, Odds).
Results in swi-prolog:
% Using 0 as an example - it of course fails
?- between(0, 6, Upper), between_evens_odds(Upper, Ev, EvT, Od).
Upper = 1,
Ev = EvT,
Od = [1] ;
Upper = 2,
Ev = [2|EvT],
Od = [1] ;
Upper = 3,
Ev = [2|EvT],
Od = [1, 3] ;
Upper = 4,
Ev = [2, 4|EvT],
Od = [1, 3] ;
Upper = 5,
Ev = [2, 4|EvT],
Od = [1, 3, 5] ;
Upper = 6,
Ev = [2, 4, 6|EvT],
Od = [1, 3, 5].
Here's the magic of difference lists - since we've already iterated through the list of Evens to the end, we can grab the tail of Evens, rather than iterate through all of Evens yet again using append, for performance:
?- between_evens_odds(5, Ev, EvT, Od), EvT = Od.
Ev = [2, 4, 1, 3, 5],
EvT = Od, Od = [1, 3, 5].
A simple and efficient implementation:
separate_odd_even(N, Odd, Even) :-
odd_even_loop(1, N, Odd, Even).
odd_even_loop(M, N, Odd, Even) :-
Bool is sign(abs(N-M)), % reify equality between M and N to avoid non-determinism
odd_even_case(Bool, M, N, Odd, Even).
odd_even_case(0, M, _, [M], []). % M and N are equal
odd_even_case(1, M, N, [M|Odd], Even) :- % M and N are different
M1 is M + 1,
odd_even_loop(M1, N, Even, Odd).
Examples:
?- separate_odd_even(8, O, E).
O = [1, 3, 5, 7],
E = [2, 4, 6, 8].
?- separate_odd_even(9, O, E).
O = [1, 3, 5, 7, 9],
E = [2, 4, 6, 8].
?- separate_odd_even(3, [1,3], E).
E = [2].
?- separate_odd_even(3, O, [2]).
O = [1, 3].
?- separate_odd_even(3, [1,3], [2]).
true.
?- separate_odd_even(3, [1,2], [3]).
false.
?- time(separate_odd_even(1000000, O, E)).
% 3,000,001 inferences, 0.313 CPU in 0.312 seconds (100% CPU, 9600003 Lips)
O = [1, 3, 5, 7, 9, 11, 13, 15, 17|...],
E = [2, 4, 6, 8, 10, 12, 14, 16, 18|...].
I received this problem and I can't get it done, I don't know what I've done wrong, can someone help me ?
Write a predicate to add a value v after 1-st, 2-nd, 4-th, 8-th, … element in a list.
% add(L:list, E:Number, P:Number, C:number, H:List)
% add(i,i,i,i,o)
add([],_,_,_,[]).
add([_|T],E,P,C,[HR|TR]) :-
P =:= C,
HR is E,
C is C+1,
P is P*2,
add(T,E,P,C,TR).
add([H|T],E,P,C,[H|TR]) :-
P =\= C,
C is C+1,
add(T,E,P,C,TR).
Here's another possibility to define such a predicate. Whenever you are describing lists it is worthwhile to consider using DCGs since they yield easily readable code. First let's observe that there's only need for three arguments, namely the list, the element to be inserted and the list with the element already inserted at the desired positions. The arguments P and C are only needed for bookkeeping purposes so it's opportune to hide them inside the predicate. And since we're already about to redesign the predicates interface let's also give it a more descriptive name that reflects its relational nature, say list_e_inserted/3:
list_e_inserted(L,E,I) :-
phrase(inserted(L,E,1,1),I). % the DCG inserted//4 describes the list I
inserted([],_E,_P,_C) --> % if the list L is empty
[]. % the list I is empty as well
inserted([H|T],E,P,P) --> % if P and C are equal
{P1 is P*2, C1 is P+1}, % P is doubled and C is increased
[H,E], % H is in the list I, followed by E
inserted(T,E,P1,C1). % the same holds for T,E,P1,C1
inserted([H|T],E,P,C) --> % if P and C are
{dif(P,C), C1 is C+1}, % different C is increased
[H], % H is in the list I
inserted(T,E,P,C1). % the same holds for T,E,P,C1
Now let's see the predicate at work:
?- list_e_inserted([],10,I).
I = [].
?- list_e_inserted([1],10,I).
I = [1, 10] ;
false.
?- list_e_inserted([1,2],10,I).
I = [1, 10, 2, 10] ;
false.
?- list_e_inserted([1,2,3],10,I).
I = [1, 10, 2, 10, 3] ;
false.
?- list_e_inserted([1,2,3,4],10,I).
I = [1, 10, 2, 10, 3, 4, 10] ;
false.
The predicate also works in the other direction:
?- list_e_inserted(L,E,[1,10,2,10,3,4,10,5]).
L = [1, 2, 3, 4, 5],
E = 10 ;
false.
And the most general query also yields the desired solutions:
?- list_e_inserted(L,E,I).
L = I, I = [] ;
L = [_G23],
I = [_G23, E] ;
L = [_G23, _G35],
I = [_G23, E, _G35, E] ;
L = [_G23, _G35, _G47],
I = [_G23, E, _G35, E, _G47] ;
L = [_G23, _G35, _G47, _G53],
I = [_G23, E, _G35, E, _G47, _G53, E] ;
.
.
.
The main problem is that when a variable in Prolog gets instantiated you can't change the value e.g increase the value so you need to use a new variable:
add([],_,_,_,[]).
add([H|T],E,P,C,[H,E|TR]) :-
P =:= C,
C1 is C+1,
P1 is P*2,
add(T,E,P1,C1,TR).
add([H|T],E,P,C,[H|TR]) :-
P =\= C,
C1 is C+1,
add(T,E,P,C1,TR).
Example:
?- add([1,2,3,4],10,1,1,L).
L = [1, 10, 2, 10, 3, 4, 10] ;
false.
I want to sum all list elements greater than some given number. Here's the description:
sumup(L, N, GREATN, GEN) sums up the members of list L which are greater than GREATN to a variable N and puts these members into the list GEN.
Sample query:
?- sumup([8, 6, 10, 3, 9, 12], N, 7, GEN).
GEN = [8, 10, 9, 12], % expected answer
N = 39. % 8+10+9+12 = 39
Following is my code:
sum_list([], 0).
sum_list([H|T], Sum) :-
H > 3,
sum_list(T, Rest),
Sum is H + Rest.
sum_list([H|T], Sum) :-
H < 3,
write('').
I've tried the recursive way but I failed. How can I fix it?
Looking at your question and your code, I noticed a few things:
While you speak of "numbers" several times, your samples are integer-only. May we neglect non-integer numbers (float, rational) and handle integers only? I guess so.
There is an auto-loaded SWI-Prolog library(lists) predicate sum_list/2.
Calling your predicate sum_list/2 is an unfortunate choice.
Let's pick another name!
Your definition of sum_list/2 comprises three clauses:
sum_list([], 0).
Okay!
sum_list([H|T], Sum) :- H > 3, sum_list(T, Rest), Sum is H + Rest.
Notice H > 3? Why hardcode the constant integer 3?
sum_list([H|T], Sum) :- H < 3, write('').
That clause is not recursive. We need to see all list elements to calculate the sum, not stop at the first list element H that fulfills H < 3!
What's the use of write('')? I don't see any.
What good is the goal H < 3? Like above, why hardcode the integer 3?
Clause #2 covers H > 3. Clause #3 covers H < 3. What about H = 3?
In this answer we use clpfd, which is present in swi-prolog.
Here's a straight-forward definition of sumup/4 based on clpfd. While it could be improved in several ways (better determinism, accumulator-style, possibly some clever redundant constraints could also help), but for the time being it's a nice first shot:
:- use_module(library(clpfd)).
sumup([], 0, _, []).
sumup([Z|Zs], S0, P, [Z|Xs]) :-
Z #> P,
S0 #= S+Z,
sumup(Zs, S, P, Xs).
sumup([Z|Zs], S, P, Xs) :-
Z #=< P,
sumup(Zs, S, P, Xs).
Sample query as given by the OP:
?- sumup([8,6,10,3,9,12], N, 7, GEN).
N = 39, GEN = [8,10,9,12] % expected answer
; false. % leftover useless choicepoint
No need to write recursive code! Just use tfilter/3, (#<)/3, and clpfd:sum/3 like this:
:- use_module(library(clpfd)).
sumup(Zs, S, P, Xs) :-
tfilter(#<(P), Zs, Xs),
sum(Xs, #=, S).
Sample query:
?- sumup([8,6,10,3,9,12], S, 7, Xs).
S = 39, Xs = [8,10,9,12]. % expected result
Note that above query succeeds deterministically—a clear improvement over this previous answer!
Bonus! As the implementation of sumup/4 is monotonic, we know that the solution of above query is also part of the solution set of every generalization of the query. Look for yourself!
?- sumup([8,6,10,3,9,12], S, E, Xs).
S = 48, E in inf..2 , Xs = [8,6,10,3,9,12]
; S = 45, E in 3..5 , Xs = [8,6,10, 9,12]
; S = 39, E in 6..7 , Xs = [8, 10, 9,12] % <==== solution of above query
; S = 31, E in 8..8 , Xs = [10, 9,12]
; S = 22, E in 9..9 , Xs = [10, 12]
; S = 12, E in 10..11 , Xs = [12]
; S = 0, E in 12..sup, Xs = []
; false.
In SWI-Prolog you can use a fold and simply query:
L=[8, 6, 10, 3, 9, 12], include(<(7),L,Gen), foldl(plus,Gen,0,N).
so that sumup would be written as
sumup(L,N,GreatN,Gen) :-
include(<(GreatN),L,Gen),
foldl(plus,Gen,0,N).
plus/3 is an arithmetic predicate that works well in our case.
I need to make a predicate that receives a numeric list and print only the numbers that end in 7 and that the sum of its digits is greater than 100
I made the predicates for separated but I need help making a union of the two predicates, I mean that the two predicates go into one only predicate, this is what I did so far:
%sum of digits greater than 100
multi(X):-
0 is X mod 100
sum([],0).
sum([P|Q],Z).
multi(P), sum(Q,Z1), Z is P + Z1.
sum([P|Q],Z).
not multi(P), sum(Q,Z).
%print the numbers that end in 7
end(Y):-
7 is Y mod 10.
listend([],0).
listend([P|Q]):-
end(P),write(P), nl, listend(Q).
listend([P|Q]):-
not(end(P)), listend(Q).
Use clpfd!
:- use_module(library(clpfd)).
We do it like this:
n_base10(N, Ds) :-
n_base_digits(N, 10, Ds).
n_base_digits(Expr, Base, Ds) :-
Base #> 1,
Ds = [_|_],
N #= Expr,
N #>= 0, % N is non-negative
n_base_ref_acc_digits(N, Base, Ds, [], Ds).
n_base_ref_acc_digits(N, Base, Ref, Ds0, Ds) :-
zcompare(Order, N, Base),
order_n_base_ref_acc_digits(Order, N, Base, Ref, Ds0, Ds).
order_n_base_ref_acc_digits(<, N, _, [_] , Ds0, [N|Ds0]).
order_n_base_ref_acc_digits(=, _, _, [_,_] , Ds0, [1,0|Ds0]).
order_n_base_ref_acc_digits(>, N, Base, [_|Rs], Ds0, Ds) :-
N0 #= N // Base,
N1 #= N mod Base,
n_base_ref_acc_digits(N0, Base, Rs, [N1|Ds0], Ds).
Some simple queries1:
?- n_base10(_, []).
false.
?- X #< 0, n_base10(X, Ds).
false.
?- n_base10(123, [1,2,3]).
true.
?- n_base10(123, Ds).
Ds = [1,2,3].
?- n_base10(N, [1,7,9]).
N = 179
; false.
?- n_base10(459183754813957135135239458256, Ds).
Ds = [4,5,9,1,8,3,7,5,4,8,1,3,9,5,7,1,3,5,1,3,5,2,3,9,4,5,8,2,5,6].
How about using bases other than 10?
?- member(Base,[2,8,10,16,36]), n_base_digits(N,Base,[1,2,3,4]).
Base = 8, N = 668
; Base = 10, N = 1234
; Base = 16, N = 4660
; Base = 36, N = 49360
; false.
?- member(Base,[2,8,10,16,36]), n_base_digits(101,Base,Ds).
Base = 2, Ds = [1,1,0,0,1,0,1]
; Base = 8, Ds = [1,4,5]
; Base = 10, Ds = [1,0,1]
; Base = 16, Ds = [6,5]
; Base = 36, Ds = [2,29].
OK! Works as expected.
Let's find integers with digit sum greater than 100 and 7 as the least significant decimal digit!
?- set_prolog_flag(toplevel_print_anon, false).
true.
?- _S #> 100,
n_base10(N, _Ds),
lists:last(_Ds, 7),
clpfd:sum(_Ds, #=, _S),
clpfd:labeling([ff,min(N)], _Ds).
N = 499999999997
; N = 589999999997
; N = 598999999997
...
Now, on to the "filtering" part of your question... it's as easy as 1, 2, 3.
First, we define (#)/2 based on (#)/1 . It fits the reification scheme (of if_/3, (=)/3, etc.) which already has been used in a lot of logically-pure Prolog answers on StackOverflow.
#(G_0, T) :- #var(T), #G_0, T = true.
Second, we define reified versions of the clpfd predicates (#=)/2 and (#>)/2.
#=(X, Y, T) :- X #= Y #<==> B, bool01_t(B, T).
#>(X, Y, T) :- X #> Y #<==> B, bool01_t(B, T).
Last, using Prolog lambdas, tfilter/3 and ','/3, we inquire:
?- use_module(library(lambda)).
true.
?- Zs0 = [ /* Es: list of sample integers */
499999999997, /* (digit sum = 101) */
9899999999970, /* (digit sum = 105) */
516666669999997, /* (digit sum = 103) */
5000007, /* (digit sum = 12) */
598999999997 /* (digit sum = 101) */
],
tfilter(\N^( /* N: candidate integer */
#n_base10(N, Ds), /* Ds: base-10 representation */
#lists:last(Ds, D1), /* D1: least significant digit */
D1 #= 7, /* D1: equal to 7 */
#clpfd:sum(Ds, #=, S), /* S: digit sum */
S #> 100 /* S: greater than 100 */
),
Zs0,
Zs).
Zs0 = [499999999997,9899999999970,516666669999997,5000007,598999999997],
Zs = [499999999997, 516666669999997, 598999999997].
Works like a charm!
Footnote 1: Using SWI-Prolog version 7.3.10 (64-bit AMD64)
This works for me:
?- filter([147, 24, 57, 17, 3667], X), write(X), nl, fail.
sumdigits(0, 0).
sumdigits(X, Z) :-
X > 0,
Z1 is X mod 10,
X2 is X // 10,
sumdigits(X2, Z2),
Z is Z1 + Z2.
filter([], []).
filter([H|X], [H|Y]) :-
sumdigits(H, D),
D > 10,
7 is H mod 10, !,
filter(X, Y).
filter([_|X], Y) :- filter(X, Y).
I get:
[147, 57, 3667]
No.
I assumed you meant that the sum of the digits was greater than 10, rather than 100.
I'm trying to get all numbers between 10 and 40 (inclusive) from a list, and outputting to another list. So far my code sort of works but does not yield the desired result. The catch is that I can't use system predicates.
rangeTenForty([], List2).
rangeTenForty([H|T], List2) :- H >= 10, T =< 40, rangeTenForty(T, List2).
rangeTenForty([H|T], List2) :- rangeTenForty(T, List2).
A few conditions:
?- rangeTenForty([400, 13, 20, 50], X). returns the answer X = [13, 20], a query
?- rangeTenForty([100, 5, 77], X). returns the answer X = [], but a query
?- rangeTenForty([12,25,2004], [12,2004]). must return the answer no.
Any help is really really really appreciated. Thanks very much.
You need to correct a few things.
rangeTenForty([], []).
rangeTenForty([H|T], [H|L]):- H >= 10, H =< 40, rangeTenForty(T, L).
rangeTenForty([H|T], L):- (H < 10;H > 40), rangeTenForty(T, L).