The question is to find the last but one character in a list, e.g.
?- last_but_one(X, [a,b,c,d]).
X = c.
My code is:
last_but_one(X, [X,_]).
last_but_one(X, [_|T]) :- last_but_one(X, T).
and the code they gave is:
last_but_one(X, [X,_]).
last_but_one(X, [_,Y|Ys]) :- last_but_one(X, [Y|Ys]).
When I was studying Haskell, I can recall that when questions asked for the 2nd, 3rd, or nth character in some list, the structure was the same as the answer that's been supplied, so I know writing it the way they've written it has some significance. But I still seem to get correct answers with the way I have written it.
Is the way I have written it wrong? Is the code that the guys who made the answer wrote better—and if so, how?
Your original version is much simpler to read. In particular, the recursive rule reads - reading it right-to-left
last_but_one(X, [_|T]) :- last_but_one(X, T).
^^^^^^^^^^
provided X is the lbo-element in T
^^ then, it follows, that (that's an arrow!)
^^^^^^^^^^^^^^^^^^^^^^
X is also the lbo-element of T with one more element
In other words: If you have already an lbo-element in a given list T, then you can construct new lists with any further elements in front that also have the very same lbo-element.
One might debate which version is preferable as to efficiency. If you are really into that, rather take:
last_but_one_f1(E, Es) :-
Es = [_,_|Xs],
xs_es_lbo(Xs, Es, E).
xs_es_lbo([], [E|_], E).
xs_es_lbo([_|Xs], [_|Es], E) :-
xs_es_lbo(Xs, Es, E).
or even:
last_but_one_f2(E, [F,G|Es]) :-
es_f_g(Es, F, G, E).
es_f_g([], E, _, E).
es_f_g([G|Es], _, F, E) :-
es_f_g(Es, F, G, E).
Never forget general testing:
?- last_but_one(X, Es).
Es = [X,_A]
; Es = [_A,X,_B]
; Es = [_A,_B,X,_C]
; Es = [_A,_B,_C,X,_D]
; Es = [_A,_B,_C,_D,X,_E]
; Es = [_A,_B,_C,_D,_E,X,_F]
; false.
And here are some benchmarks on my olde labtop:
SICStus SWI
4.3.2 7.3.20-1
--------------+----------+--------
you 0.850s | 3.616s | 4.25×
they 0.900s | 16.481s | 18.31×
f1 0.160s | 1.625s | 10.16×
f2 0.090s | 1.449s | 16.10×
mat 0.880s | 4.390s | 4.99×
dcg 3.670s | 7.896s | 2.15×
dcgx 1.000s | 7.885s | 7.89×
ap 1.200s | 4.669s | 3.89×
The reason for the big difference is that both f1 and f2 run purely determinate without any creation of a choicepoint.
Using
bench_last :-
\+ ( length(Ls, 10000000),
member(M, [you,they,f1,f2,mat,dcg,dcgx,ap]), write(M), write(' '),
atom_concat(last_but_one_,M,P), \+ time(call(P,L,Ls))
).
Here is another approach using DCGs. I think that this solution is much more "graphical", but it seems quite slow in SICStus:
last_but_one_dcg(L, Ls) :-
phrase( ( ..., [L,_] ), Ls).
... --> [].
... --> [_], ... .
So we describe how a list must look like such that it has a last-but-one element. It looks like this: Anything (...) in front, and then two elements at the end.
It gets a bit faster by expanding phrase/2. Note that the expansion itself is no longer a conforming program.
last_but_one_dcgx(L, Ls) :-
...(Ls, Ls2),
Ls2 = [L,_].
I would say both answers are just as good and I would probably have written it the way you did. What they do in the second solution is that they check, before the recursive call, that the second element is not a empty list ([]). If you trace the two different solutions on the following query: last_but_one(X,[b]).
You'll see that both give the same answer (false), but the second solution takes shorter amount of steps since it returns false before the recursive call is made.
I agree with #false that your own version is simpler to read.
Personally, I find using a DCG (see dcg) even easier:
last_but_one(X) --> [X,_].
last_but_one(X) -->
[_],
last_but_one(X).
As interface predicate, you can use:
last_but_one(L, Ls) :-
phrase(last_but_one(L), Ls).
I now would like to add some actual timings.
We have 3 versions for comparison:
the DCG version, which I call last_but_one//1
your own version, which I call last_but_one_you/2
their version, which I call last_but_one_they/2.
The test case consists of finding the penultimate element of a list with ten million elements.
We have:
?- length(Ls, 10_000_000), time(last_but_one(L, Ls)), false.
9,999,999 inferences, 1.400 CPU in 1.400 seconds (100% CPU, 7141982 Lips)
?- length(Ls, 10_000_000), time(last_but_one_you(L, Ls)), false.
9,999,998 inferences, 1.383 CPU in 1.383 seconds (100% CPU, 7229930 Lips)
?- length(Ls, 10_000_000), time(last_but_one_they(L, Ls)), false.
9,999,998 inferences, 5.566 CPU in 5.566 seconds (100% CPU, 1796684 Lips)
This shows that not only is the version that they provided much harder to read, it is also by far the slowest for this benchmark.
Always aim for elegance and readability first. Very often, you also obtain a fast version if you follow this principle.
Here are more ways how you could do it.
I wouldn't recommend actually using any of the following methods, but IMO they are interesting as they give a different view on the other codes and on the Prolog library provided by the respective Prolog processors:
In the first three variants, we delegate the "recursive part" to built-in / library predicates:
last_but_one_append(X,Es) :-
append(_, [X,_], Es).
:- use_module(library(lists)).
last_but_one_reverse(X, Es) :-
reverse(Es, [_,X|_]).
last_but_one_rev(X, Es) :-
rev(Es, [_,X|_]). % (SICStus only)
Alternatively, we could use vanilla home-brewed myappend/3 and myreverse/2:
myappend([], Bs, Bs).
myappend([A|As], Bs, [A|Cs]) :-
myappend(As, Bs, Cs).
last_but_one_myappend(X, Es) :-
myappend(_, [X,_], Es).
myreverse(Es, Fs) :-
same_length(Es, Fs), % for universal termination in mode (-,+)
myreverse_(Es, Fs, []).
myreverse_([], Fs, Fs).
myreverse_([E|Es], Fs, Fs0) :-
myreverse_(Es, Fs, [E|Fs0]).
last_but_one_myreverse(X, Es) :-
myreverse(Es, [_,X|_]).
Let's run the experiments1!
bench_last :-
\+ ( length(Ls, 10000000),
member(M, [you,they,f1,f2,mat,dcg,dcgx,ap,
append,reverse,rev,
myappend,myreverse]),
write(M), write(' '),
atom_concat(last_but_one_,M,P),
\+ time(call(P,_L,Ls))
).
Here are the runtimes2 using SICStus Prolog and SWI-Prolog3,4:
SICStus | SICStus | SWI |
4.3.2 | 4.3.3 | 7.3.20 |
-------------------+---------+--------|
you 0.26s | 0.10s | 0.83s | 3.1× 8.3×
they 0.27s | 0.12s | 1.03s | 3.8× 8.5×
f1 0.04s | 0.02s | 0.43s | 10.8× 21.5×
f2 0.02s | 0.02s | 0.37s | 18.5× 18.5×
mat 0.26s | 0.11s | 1.02s | 3.9× 9.0×
dcg 1.06s | 0.77s | 1.47s | 1.3× 1.9×
dcgx 0.31s | 0.17s | 0.97s | 3.1× 5.7×
ap 0.23s | 0.11s | 0.42s | 1.8× 3.8×
append 1.50s | 1.13s | 1.57s | 1.0× 1.3×
reverse 0.36s | 0.32s | 1.02s | 2.8× 3.1×
rev 0.04s | 0.04s | --"-- | 25.6× 25.6×
myappend 0.48s | 0.33s | 1.56s | 3.2× 4.7×
myreverse 0.27s | 0.26s | 1.11s | 4.1× 4.2×
Edit: Added SICStus Prolog 4.3.3 benchmarking data
Very impressive! In the SICStus/SWI speedup column, differences > 10% got bold-faced.
Footnote 1: All measurements shown in this answer were obtained on an Intel
Haswell processor
Core i7-4700MQ.
Footnote 2: rev/2 is offered by SICStus—but not by SWI. We compare the fastest "reverse" library predicate.
Footnote 3: The SWI command-line option -G1G was required to prevent Out of global stack errors.
Footnote 4: Also, the SWI command-line option -O (optimize) was tried, but did not yield any improvement.
another solution :
firstly, the list must be of length >= 2,
also the last length element of the list = 1
code :
last_but_one(R,[X|Rest]):-
( Rest=[_], R=X
; last_but_one(R,Rest)
).
Test :
| ?- last_but_one(Elem,List).
List = [Elem,_A] ? ;
List = [_A,Elem,_B] ? ;
List = [_A,_B,Elem,_C] ? ;
List = [_A,_B,_C,Elem,_D] ? ;
List = [_A,_B,_C,_D,Elem,_E] ? ;
List = [_A,_B,_C,_D,_E,Elem,_F] ? ;
List = [_A,_B,_C,_D,_E,_F,Elem,_G] ? ;
List = [_A,_B,_C,_D,_E,_F,_G,Elem,_H] ?
yes
Hope this idea help you
Related
The question is to find the last but one character in a list, e.g.
?- last_but_one(X, [a,b,c,d]).
X = c.
My code is:
last_but_one(X, [X,_]).
last_but_one(X, [_|T]) :- last_but_one(X, T).
and the code they gave is:
last_but_one(X, [X,_]).
last_but_one(X, [_,Y|Ys]) :- last_but_one(X, [Y|Ys]).
When I was studying Haskell, I can recall that when questions asked for the 2nd, 3rd, or nth character in some list, the structure was the same as the answer that's been supplied, so I know writing it the way they've written it has some significance. But I still seem to get correct answers with the way I have written it.
Is the way I have written it wrong? Is the code that the guys who made the answer wrote better—and if so, how?
Your original version is much simpler to read. In particular, the recursive rule reads - reading it right-to-left
last_but_one(X, [_|T]) :- last_but_one(X, T).
^^^^^^^^^^
provided X is the lbo-element in T
^^ then, it follows, that (that's an arrow!)
^^^^^^^^^^^^^^^^^^^^^^
X is also the lbo-element of T with one more element
In other words: If you have already an lbo-element in a given list T, then you can construct new lists with any further elements in front that also have the very same lbo-element.
One might debate which version is preferable as to efficiency. If you are really into that, rather take:
last_but_one_f1(E, Es) :-
Es = [_,_|Xs],
xs_es_lbo(Xs, Es, E).
xs_es_lbo([], [E|_], E).
xs_es_lbo([_|Xs], [_|Es], E) :-
xs_es_lbo(Xs, Es, E).
or even:
last_but_one_f2(E, [F,G|Es]) :-
es_f_g(Es, F, G, E).
es_f_g([], E, _, E).
es_f_g([G|Es], _, F, E) :-
es_f_g(Es, F, G, E).
Never forget general testing:
?- last_but_one(X, Es).
Es = [X,_A]
; Es = [_A,X,_B]
; Es = [_A,_B,X,_C]
; Es = [_A,_B,_C,X,_D]
; Es = [_A,_B,_C,_D,X,_E]
; Es = [_A,_B,_C,_D,_E,X,_F]
; false.
And here are some benchmarks on my olde labtop:
SICStus SWI
4.3.2 7.3.20-1
--------------+----------+--------
you 0.850s | 3.616s | 4.25×
they 0.900s | 16.481s | 18.31×
f1 0.160s | 1.625s | 10.16×
f2 0.090s | 1.449s | 16.10×
mat 0.880s | 4.390s | 4.99×
dcg 3.670s | 7.896s | 2.15×
dcgx 1.000s | 7.885s | 7.89×
ap 1.200s | 4.669s | 3.89×
The reason for the big difference is that both f1 and f2 run purely determinate without any creation of a choicepoint.
Using
bench_last :-
\+ ( length(Ls, 10000000),
member(M, [you,they,f1,f2,mat,dcg,dcgx,ap]), write(M), write(' '),
atom_concat(last_but_one_,M,P), \+ time(call(P,L,Ls))
).
Here is another approach using DCGs. I think that this solution is much more "graphical", but it seems quite slow in SICStus:
last_but_one_dcg(L, Ls) :-
phrase( ( ..., [L,_] ), Ls).
... --> [].
... --> [_], ... .
So we describe how a list must look like such that it has a last-but-one element. It looks like this: Anything (...) in front, and then two elements at the end.
It gets a bit faster by expanding phrase/2. Note that the expansion itself is no longer a conforming program.
last_but_one_dcgx(L, Ls) :-
...(Ls, Ls2),
Ls2 = [L,_].
I would say both answers are just as good and I would probably have written it the way you did. What they do in the second solution is that they check, before the recursive call, that the second element is not a empty list ([]). If you trace the two different solutions on the following query: last_but_one(X,[b]).
You'll see that both give the same answer (false), but the second solution takes shorter amount of steps since it returns false before the recursive call is made.
I agree with #false that your own version is simpler to read.
Personally, I find using a DCG (see dcg) even easier:
last_but_one(X) --> [X,_].
last_but_one(X) -->
[_],
last_but_one(X).
As interface predicate, you can use:
last_but_one(L, Ls) :-
phrase(last_but_one(L), Ls).
I now would like to add some actual timings.
We have 3 versions for comparison:
the DCG version, which I call last_but_one//1
your own version, which I call last_but_one_you/2
their version, which I call last_but_one_they/2.
The test case consists of finding the penultimate element of a list with ten million elements.
We have:
?- length(Ls, 10_000_000), time(last_but_one(L, Ls)), false.
9,999,999 inferences, 1.400 CPU in 1.400 seconds (100% CPU, 7141982 Lips)
?- length(Ls, 10_000_000), time(last_but_one_you(L, Ls)), false.
9,999,998 inferences, 1.383 CPU in 1.383 seconds (100% CPU, 7229930 Lips)
?- length(Ls, 10_000_000), time(last_but_one_they(L, Ls)), false.
9,999,998 inferences, 5.566 CPU in 5.566 seconds (100% CPU, 1796684 Lips)
This shows that not only is the version that they provided much harder to read, it is also by far the slowest for this benchmark.
Always aim for elegance and readability first. Very often, you also obtain a fast version if you follow this principle.
Here are more ways how you could do it.
I wouldn't recommend actually using any of the following methods, but IMO they are interesting as they give a different view on the other codes and on the Prolog library provided by the respective Prolog processors:
In the first three variants, we delegate the "recursive part" to built-in / library predicates:
last_but_one_append(X,Es) :-
append(_, [X,_], Es).
:- use_module(library(lists)).
last_but_one_reverse(X, Es) :-
reverse(Es, [_,X|_]).
last_but_one_rev(X, Es) :-
rev(Es, [_,X|_]). % (SICStus only)
Alternatively, we could use vanilla home-brewed myappend/3 and myreverse/2:
myappend([], Bs, Bs).
myappend([A|As], Bs, [A|Cs]) :-
myappend(As, Bs, Cs).
last_but_one_myappend(X, Es) :-
myappend(_, [X,_], Es).
myreverse(Es, Fs) :-
same_length(Es, Fs), % for universal termination in mode (-,+)
myreverse_(Es, Fs, []).
myreverse_([], Fs, Fs).
myreverse_([E|Es], Fs, Fs0) :-
myreverse_(Es, Fs, [E|Fs0]).
last_but_one_myreverse(X, Es) :-
myreverse(Es, [_,X|_]).
Let's run the experiments1!
bench_last :-
\+ ( length(Ls, 10000000),
member(M, [you,they,f1,f2,mat,dcg,dcgx,ap,
append,reverse,rev,
myappend,myreverse]),
write(M), write(' '),
atom_concat(last_but_one_,M,P),
\+ time(call(P,_L,Ls))
).
Here are the runtimes2 using SICStus Prolog and SWI-Prolog3,4:
SICStus | SICStus | SWI |
4.3.2 | 4.3.3 | 7.3.20 |
-------------------+---------+--------|
you 0.26s | 0.10s | 0.83s | 3.1× 8.3×
they 0.27s | 0.12s | 1.03s | 3.8× 8.5×
f1 0.04s | 0.02s | 0.43s | 10.8× 21.5×
f2 0.02s | 0.02s | 0.37s | 18.5× 18.5×
mat 0.26s | 0.11s | 1.02s | 3.9× 9.0×
dcg 1.06s | 0.77s | 1.47s | 1.3× 1.9×
dcgx 0.31s | 0.17s | 0.97s | 3.1× 5.7×
ap 0.23s | 0.11s | 0.42s | 1.8× 3.8×
append 1.50s | 1.13s | 1.57s | 1.0× 1.3×
reverse 0.36s | 0.32s | 1.02s | 2.8× 3.1×
rev 0.04s | 0.04s | --"-- | 25.6× 25.6×
myappend 0.48s | 0.33s | 1.56s | 3.2× 4.7×
myreverse 0.27s | 0.26s | 1.11s | 4.1× 4.2×
Edit: Added SICStus Prolog 4.3.3 benchmarking data
Very impressive! In the SICStus/SWI speedup column, differences > 10% got bold-faced.
Footnote 1: All measurements shown in this answer were obtained on an Intel
Haswell processor
Core i7-4700MQ.
Footnote 2: rev/2 is offered by SICStus—but not by SWI. We compare the fastest "reverse" library predicate.
Footnote 3: The SWI command-line option -G1G was required to prevent Out of global stack errors.
Footnote 4: Also, the SWI command-line option -O (optimize) was tried, but did not yield any improvement.
another solution :
firstly, the list must be of length >= 2,
also the last length element of the list = 1
code :
last_but_one(R,[X|Rest]):-
( Rest=[_], R=X
; last_but_one(R,Rest)
).
Test :
| ?- last_but_one(Elem,List).
List = [Elem,_A] ? ;
List = [_A,Elem,_B] ? ;
List = [_A,_B,Elem,_C] ? ;
List = [_A,_B,_C,Elem,_D] ? ;
List = [_A,_B,_C,_D,Elem,_E] ? ;
List = [_A,_B,_C,_D,_E,Elem,_F] ? ;
List = [_A,_B,_C,_D,_E,_F,Elem,_G] ? ;
List = [_A,_B,_C,_D,_E,_F,_G,Elem,_H] ?
yes
Hope this idea help you
I have to write a predicate insort/2 which reduces any list (with possibly
duplicated elements) to a list in which each distinct element appears only once
and a specific order is used. For example,
? - insort([a,[a,a],[a,b],[b,a],[[a,b]],[d],c],X).
X = [a,c,[a],[d],[a,b],[[a,b]]]
yes
? - insort([[a,[a,b]],[a,[c,b]],[[a,b],a]], X).
X = [[a,[a,b]],[a,[b,c]]]
yes
? - insort([[a,b],[a,[a]],[a,b,c]],X).
X = [[a,b],[a,[a]],[a,b,c]]
yes
The order should first examine the total length of the list and the list with smaller total length is “smaller”. If total length is the
same then the natural order of terms in PROLOG should be adopted. But final solution cannot use SWI-Prolog built-in sort/2 and merge/3 predicates.
My work for now is like that:
rlen([],0).
rlen(X,1).
rlen([Head|Tail],N):-rlen(Head,Q1),rlen(Tail,Q2),N is Q1+Q2.
member(Head, [Head|Tail]).
member(X, [Head|Tail]) :- member(X,Tail).
remove_duplicates([],[]).
remove_duplicates([H | T], List) :-
member(H, T),
remove_duplicates( T, List).
remove_duplicates([H | T], [H|T1]) :-
\+member(H, T),
remove_duplicates( T, T1).
count(_,[],0).
count(X,[X],1).
count(X, [X|Y],N):- count(X,Y,W),N is W + 1.
count(Z,[X|Y],N):- count(Z,Y,N),X\=Z.
elsort([],[]).
elsort([A|B],C):-
elsort(B,D),
(is_list(A)->elsort(A, SA);SA=A),
elsortx(SA,D,C).
elsortx(A,[X|B],[X|C]):-
order(X,A),
!,
elsortx(A,B,C).
elsortx(A,B,[A|B]).
order(X,Y) :- is_list(X), is_list(Y), length(X,A),length(Y,B),A<B.
order(A,A2):-
A #< A2.
But still missing some things, I don't know how use here remove_duplicates,
and why order([[a,b]],[a,b]). throws true, should be false
Thanks for help, I really don't know how handle this
I have the list [r,s,2,t,3,u,v] and I need to make a list that will look like [r,5,s,2,t,3,u,5,v,5]. The rule is: for every non integer that is not followed by an integer, a 5 will be added after that element.
I am new to Prolog and this is my code so far:
insertInL([],[]).
insertInL([F,S|Tail], [F,X|Rest]) :-
integer(S), X = S, insertInL(Tail, Rest).
I know there should be one case where S is not an integer but I don't know hot to treat it.
Edit:
I renewed my code:
insertInL([],[]).
insertInL([F,S|T1], [F,S|T2]) :-
integer(S), insertInL(T1, T2).
insertInL([F,S|T1], [F,1|T2]) :-
\+ integer(S), insertInL([S|T1], T2).
Now it does fine unless I have a non integer as last element.
Edit2:
Now it works properly.
insertInL([],[]).
insertInL([F],[F,1]) :-
\+ integer(F).
insertInL([F,S|T1], [F,S|T2]) :-
integer(S), insertInL(T1, T2),!.
insertInL([F,S|T1], [F,1|T2]) :-
\+ integer(S), insertInL([S|T1], T2).
Here's how you could do it while preserving logical-purity!
Based on if_/3 and integer_t/2 we define:
list_fived([], []).
list_fived([X|Xs], [X|Ys]) :-
if_(integer_t(X),
list_fived(Xs, Ys),
past_nonint(Xs, Ys)).
past_nonint([], [5]).
past_nonint([X|Xs], Ys0) :-
if_(integer_t(X),
(Ys0 = [X|Ys], list_fived(Xs, Ys)),
(Ys0 = [5|Ys], list_fived([X|Xs], Ys))).
Sample query using SICStus Prolog 4.3.2:
| ?- list_fived([r,s,2,t,3,u,v], Xs).
Xs = [r,5,s,2,t,3,u,5,v,5] ? ; % expected result as given by the OP
no
I've been trying to sort a list of structure.
The structure is like this
% person(Name, Weight).
person(tom, 65).
person(dan, 70).
person(mike, 80).
And the list would be like this
List = [person(tom, 65), person(dan, 70), person(mike, 80)].
I want to sort the list from greatest weight to least. Like this:
SortList = [person(mike, 80), person(dan, 70), person(tom, 65)].
So far I have this:
sortListPerson([], []).
sortListPerson([person(NameP, WP)|Rest], Result):-
sortListPerson(Rest, List),
insertPerson(person(NameP, WP), List, Result).
insertPerson(person(NameP, WP), [], [person(NameP, WP)]).
insertPerson(person(NameP1, WP1), [person(NameP2, WP2)|Rest], [person(NameP1, WP1)|List]):-
integer(WP1),
integer(WP2),
WP1 #>= WP2,
insertPerson(person(NameP2, WP2), Rest, List).
insertPerson(person(NameP1, WP1), [person(NameP2, WP2)|Rest], [person(NameP2, WP2)|List]):-
integer(WP1),
integer(WP2),
WP1 #< WP2,
insertInPlace(person(NameP1, WP1), Rest, List).
I've tried with a list of two persons and it works:
?- sortListPerson([person(a, 10), person(b, 30)], SortList).
SortList = [person(b,30),person(a,10)] ? ;
But when I try with a list of 3 or more person appears an error:
?- sortListPerson([person(a, 10), person(b, 30), person(c, 40)], SortList).
{ERROR: arithmetic:>=/2 - expected an arithmetically evaluable expression, found person(a,10)}
no
?-
Can anybody help?
The way I see it your insertion-sort is okay, except for the second clause of insertPerson/3:
:- use_module(library(clpfd)).
insertPerson(person(N,W), [], [person(N,W)]).
insertPerson(person(N1,W1), [person(N2,W2)|Ps], [person(N1,W1),person(N2,W2)|Ps]) :-
W1 #>= W2. % If Ps is in order, we're done!
insertPerson(person(N1,W1), [person(N2,W2)|Ps], [person(N2,W2)|Qs]) :-
W1 #< W2,
insertPerson(person(N1,W1), Ps, Qs).
Sample query:
?- sortListPerson([person(tom,65),person(dan,70),person(mike,80)], Xs).
Xs = [person(mike,80),person(dan,70),person(tom,65)] ;
false.
The error comes from the fact that the built-in arithmetic operators like < and =< only work on instantiated terms (i.e. 1 < 2 is true but 1 < X throws the exception you mentioned). If you use constraints, the code becomes something like:
:- use_module(library(clpfd)).
smallest_in_rest_vars(person(N,A), [person(N,A)], [], [A]).
smallest_in_rest_vars(person(N,A), [person(N1,A1) | Ps], % <-- this one fails without clpfd
[person(N1,A1) | Rs], [A1|Vs] ) :-
A #=< A1,
smallest_in_rest_vars(person(N,A), Ps, Rs, Vs).
smallest_in_rest_vars(person(N1,A1), [person(N1,A1) | Ps],
[person(N,A) | Rs], [A1|Vs] ) :-
A #> A1,
smallest_in_rest_vars(person(N,A), Ps, Rs, Vs).
list_sorted([],[], []).
list_sorted(L, [Smallest|SortedRest], Vars) :-
smallest_in_rest_vars(Smallest, L, Rest, Vars0),
list_sorted(Rest, SortedRest, Vars1),
append(Vars0, Vars1, Vars).
I assume your insertInPlace predicate is similar to smallest_in_rest_vars, only without the explicit list of variables Vs which is useful for labeling (which we don't need in this case). If I would not use constraints, I'd get the following error when I query with your list:
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (9) smallest_in_rest_vars(_G400, [person(tom, 65), person(dan, 70), person(mike, 80)], [person(_G406, _G407)], _G462) ?
The reason is that the clause which is marked in the example, we don't know anything about the new person N1 yet, which leads to a comparison 80 < A1. I found using clpfd much easier to think about, but when you give us your insertInPlace, we might find a non-clp solution too.
So i got this for powerset:
powerset([], []).
powerset([H|T], P) :- powerset(T,P).
powerset([H|T], [H|P]) :- powerset(T,P).
This generates all sets of a list. Is it possible to generate all sets in list order.
Example:
List = [a,b,c]
I want to get
[a],[a,b],[a,b,c],[b],[b,c],[c]
Note there is no [a,c] in this list of subsets since these are subsets starting from the left and going to the right.
I've tried using a combination of append and recursion, but that didn't work out as i wanted it to. Little stumped at this point.
Thanks.
How about
powerset(L, [H|T]):-
append([H|T], _, L).
powerset([_|L], P):-
powerset(L, P).
You want all subsequences substrings (definition). Grammars (DCGs) are best for this:
seq([]) -->
[].
seq([E|Es]) -->
[E],
seq(Es).
... --> [] | [_], ... .
?- Es = [_|_], phrase((..., seq(Es), ...), [A,B,C]).
Es = [A]
; Es = [A, B]
; Es = [A, B, C]
; Es = [B]
; Es = [B, C]
; Es = [C]
; false.
I know this an old post, but I'm not gonna update it for no reasons.
the answer which is accepted with all the respect, generates all subsets separably, and does not generate a powerset.
a few days ago I was trying to implement a powerSet/2 predicate, without use of built-in predicate bagof/2. but even with bagof/2 and setof/2 it's not very easy problem for beginners (generating all subset separably is another problem and much easier). so after implementing the solution I thought it's better to put it here in order to prevent people who are searching for this topic from mistakes.
My solution (without bagof/2)
generate(X, [Y], [[X| Y]]).
generate(X, S, P) :-
S = [H| T],
append([X], H, Temp),
generate(X, T, Rest),
append([Temp], Rest, P), !.
powerSet([], [[]]).
powerSet(Set, P) :-
Set = [H| T],
powerSet(T, PsT),
generate(H, PsT, Ps),
% write('trying to push '), print(H), write(' to '),
% write('all elements of powerset of '), print(T), write(' which is '),
% print(PsT), nl,
% write('and the result is '), print(Ps), nl, nl,
append(Ps, PsT, P), !.
code will be understood if consulted with the commented lines.
another solution is available here which uses built-in predicate bagof/3.
probably it would be more helpful now.
How about this:
powerset(A,B):-
append(A,_,B);
append(_,A,B).
test():-
setof(X,powerset(X,[1,2,3]),L),
writeln(L).