Prolog: P-12: Ninety-Nine Prolog Problems (Modified) - list

I am trying to decode a specific list with two different elements, either e.g. [4, a] or just b
I expect decode([[4,a],b,[2,c],[2,a],d,[4,e]], X). to result into X=[a,a,a,a,b,c,c,a,a,d,e,e,e,e].
with
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, L1),
append(L1, R),
decode(Xs, R).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, []).
create_list(N, X, [X|R]) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R).
Generates only false and I have tested the create_list predicate and it works.
I have no clue what I'm missing but could just be a minor mistake. But I have tried for a while to find the problem without success so why not ask here :) The question is a modified version from the Ninety-Nine Prolog Problems (Problem 12).

Your problem lies in the use of append/2 which concatenates a list of lists, but you have a list of atoms.
You may use append/3 to build a list with an unbound tail and pass that tail to the recursive step of your procedure, i.e.:
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, L1),
append(L1, Tail, R),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, []).
create_list(N, X, [X|R]) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R).
Sample run:
?- decode([[4,a],b,[2,c],[2,a],d,[4,e]], X).
X = [a, a, a, a, b, c, c, a, a, d, e, e, e, e] ;
false.
You may also get rid of append altogether by adding a third argument to create_list which holds that tail:
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, R, Tail),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, Tail, Tail).
create_list(N, X, [X|R], Tail) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R, Tail).
Alternatively you may get rid of create_list by using length/2 and maplist/2:
decode([], []).
decode([[N, X]|Xs], R) :-
length(L, N),
maplist(=(X), L),
append(L, Tail, R),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).

This is a problem of run-length encoding and run-length decoding.
Run-length encoding is easy:
encode( [] , [] ) . % the run-length encoding of the empty list is the empty list
encode( [X|Xs] , [R|Ys] ) :- % For non-empty lists,
run(Xs,X:1,R,Rs), % - seed the run with the first element and compute the run length
encode(Rs, Ys) % - then recurse down
. % Easy!
run( [] , Y:N , Y:N , [] ) .
run( [X|Xs] , Y:N , Y:N , [X|Xs] ) :- X \== Y .
run( [X|Xs] , Y:T , N , Rs ) :- X == Y , T1 is T+1 , run(Xs,Y:T1,N,Rs) .
And decoding a run-length encoded list is the opposite
decode( [] , [] ) . % the run-length decoding of the empty list is the empty list
decode( [X:N|Xs] , Ys ) :- % for non-empty lists,
expand(X,N,Ys,Zs) , % - expand the run
decode(Xs,Zs) % - recurse down
.
expand( _ , 0 , Zs , Zs ) .
expand( X , N , [X|Ys] , Zs ) :-
N > 0,
N1 is N-1,
expand(X,N1,Ys,Zs)
.
And then put it together in a transcoder that will work bi-directionally:
run_length_transcode( PlainText, RleText ) :- nonvar( PlainText ) , encode( PlainText , RleText ).
run_length_transcode( PlainText, RleText ) :- nonvar( RleText ) , decode( RleText , PlainText ).

Related

Prolog: Take the first "N" elements of a list

I need to write a Prolog predicate take(L, N, L1) which succeeds if list L1 contains the first N elements of list L, in the same order. For example:
?- take([5,1,2,7], 3, L1).
L1 = [5,1,2]
?- take([5,1,2,7], 10, L1).
L1 = [5,1,2,7]
Prolog thus far is making little sense to me, and I'm having a hard time breaking it down. Here is what I have so far:
take([H|T], 0, []).
take([H|T], N, L1) :-
take(T, X, L2),
X is N-1.
Can you please explain what I did wrong here?
Here is a definition that implements the relational counterpart to take in functional languages like Haskell1. First, the argument order should be different which facilitates partial application. There is a cut, but only after the error checking built-in (=<)/2 which produces an instantiation_error should the argument contain a variable.
take(N, _, Xs) :- N =< 0, !, N =:= 0, Xs = [].
take(_, [], []).
take(N, [X|Xs], [X|Ys]) :- M is N-1, take(M, Xs, Ys).
?- take(2, Xs, Ys).
Xs = [], Ys = []
; Xs = [_A], Ys = [_A]
; Xs = [_A,_B|_C], Ys = [_A,_B].
Note how above query reads:
How can one take 2 elements from Xs to get Ys?
And there are 3 different answers. If Xs is empty, then so is Ys. If Xs is a list with one element, then so is Ys. If Xs has at least 2 elements, then those two are Ys.
1) The only difference being that take(-1, Xs,Ys) fails (for all Xs, Ys). Probably the best would be to issue a domain_error similar to arg(-1,s(1),2)
findall/3 it's a bit the 'swiss knife' of Prolog. I would use this snippet:
take(Src,N,L) :- findall(E, (nth1(I,Src,E), I =< N), L).
The code by #CapelliC works if the instantiation is right; if not, it can show erratic behavior:
?- take(Es, 0, Xs).
**LOOPS** % trouble: goal does not terminate
?- take([A,_], 1, [x]).
true. % trouble: variable A remains unbound
To safeguard against this you can use
iwhen/2 like so:
take(Src, N, L) :-
iwhen(ground(N+Src), findall(E, (nth1(I,Src,E), I =< N), L)).
Sample queries run with SWI-Prolog 8.0.0:
?- take([a,b,c,d,e,f], 3, Ls).
Ls = [a,b,c].
?- take([a,b,c,d,e,f], N, Ls).
ERROR: Arguments are not sufficiently instantiated
?- take(Es, 0, Xs).
ERROR: Arguments are not sufficiently instantiated
?- take([A,_], 1, [x]).
ERROR: Arguments are not sufficiently instantiated
Safer now!
The obvious solution would be:
take(List, N, Prefix) :-
length(List, Len),
( Len =< N
-> Prefix = List
; length(Prefix, N),
append(Prefix, _, List)
).
Less thinking means less opportunity for mistakes. It also makes the predicate more general.
your base case is fine
take([H|T], 0, []).
And also you can say what if N is 1
take([H|T],1,[H]).
But you recursive case some variable is not defined like L2. So we can write this as
take([X|T1],N,[X|T2]):-
N>=0,
N1 is N-1,
take(T1,N1,T2).
which case all varibles are pattern-matched.
take(L, N, L1) :- length(L1, N), append(L1, _, L).
This is performant, general and deterministic:
first_elements_of_list(IntElems, LongLst, ShortLst) :-
LongLst = [H|T],
( nonvar(IntElems) -> Once = true
; is_list(ShortLst) -> Once = true
; Once = false
),
first_elements_of_list_(T, H, 1, IntElems, ShortLst),
(Once = true -> ! ; true).
first_elements_of_list_([], H, I, I, [H]).
first_elements_of_list_([_|_], H, I, I, [H]).
first_elements_of_list_([H|LongLst], PrevH, Upto, IntElems, [PrevH|ShortLst]) :-
Upto1 is Upto + 1,
first_elements_of_list_(LongLst, H, Upto1, IntElems, ShortLst).
Result in swi-prolog:
?- first_elements_of_list(N, [a, b, c], S).
N = 1,
S = [a] ;
N = 2,
S = [a,b] ;
N = 3,
S = [a,b,c].
?- first_elements_of_list(2, [a, b, c], S).
S = [a,b].
Below is a variant which also supports:
?- first_elements_of_list_more(10, [5, 1, 2, 7], L1).
L1 = [5,1,2,7].
first_elements_of_list_more(IntElems, [H|LongLst], [H|ShortLst]) :-
once_if_nonvar(IntElems, first_elements_of_list_more_(LongLst, 1, IntElems, ShortLst)).
first_elements_of_list_more_([], Inc, Elems, []) :-
(var(Elems) -> Inc = Elems
; Elems >= Inc).
first_elements_of_list_more_([_|_], E, E, []).
first_elements_of_list_more_([H|LongLst], Upto, IntElems, [H|ShortLst]) :-
succ(Upto, Upto1),
first_elements_of_list_more_(LongLst, Upto1, IntElems, ShortLst).
once_if_nonvar(Var, Expr) :-
nonvar(Var, Bool),
call(Expr),
(Bool == true -> ! ; true).
nonvar(Var, Bool) :-
(nonvar(Var) -> Bool = true ; Bool = false).

List exercise on prolog

So my professor at campus asked us to solve this exercise but is kinda tough and I am trying for 2 days now. Anyway here it is:
I'm given a list for example [a,b,c,d,w,n,i,c,k,a,b,c,d,w] and on this list I have to find out if there is "suspect" sublist. The sublist is considered "suspect" if
1) the same sublist is in the beginning and at the end,
2) it contains "w",
3) its length is 5.
The list I give has a "suspect" sublist.
If there is a suspect sublist the program must return the sublist or if there is not the program must return [o,k].
Any ideas will be welcome, thanks a lot!
(sorry if i posted something wrong)
EDIT
So after some help here is the asnwer:
checkMessage1(L,SL):-
suspiciousMessage1(L,SL).
checkMessage1(L,[o,k]):-
not(suspiciousMessage1(L,SL)).
suspiciousMessage1(L,SL):-
append(SL,Last,L),
append(_,SL,Last),
length(SL,5),
member(w,SL).
Prolog is a declarative language: describe the solution in terms of constraints and let the engine do the work.
We can determine membership in a list thus:
contains( [X|Xs] , X ) :- ! .
contains( [_|Xs] , X ) :- contains(Xs,X) .
We can determine if a lists 1st element is identical to its last element using the built-in predicate append/3:
list_starts_and_ends_with_identical( [X|Xs] ) :-
append( [X|_] , [X] , [X|Xs] )
.
Or, if you'd rather roll your own:
list_starts_and_ends_with_identical( [A|Xs] ) :-
list_ends_with( Xs , A )
.
list_ends_with( [A] , A ) .
list_ends_with( [B,C|D] , A ) :-
list_ends_with( [C|D] , A )
.
And we can enumerate sublists of the desired length like so:
sublist_of_length( Xs, L , Ys ) :- % to enumerate sublists of the desired length,
integer(L) , % - validate that the length is an integer, and
L > 0 , % - validate that the length is positive, and
length(Ys,L) , % - construct a list of unbound variables of the desired length, and
sl(Ys,L) % - invoke the helper
. %
sl( [X|Xs] , L ) :- % to enumerate sublists,
append( L , _ , [X|Xs] ) % - simply get the prefix of the desired length
. %
sl( [_|Xs] , L ) :- % on backtracking,
sl( Xs , L ) % - just recurse down on the tail of the list, discarding the first element.
.
Then, all we have to do is assemble the parts:
suspect_sublist( Xs , L ) :- % the source list Xs contains a suspect sublist L, IF...
sublist_of_length( Xs , 5 , L ) , % - L is a sublist of Xs having length 5, and
contains( L , w ) , % - L contains the atom 'w', and
list_starts_and_ends_with_identical( L ) , % - the first element of L is identical to the last.
. % Easy!
This is a good example for using DCGs:
list_suspect(Xs, Ys) :-
length(Ys, 5),
phrase(( seq(Ys), ..., seq(Ys) ), Xs),
phrase((...,"w",...), Ys).
... --> [] | [_], ... .
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
And here is a version using append/3 instead:
list_suspect(Xs, Ys) :-
Ys = [_,_,_,_,_],
append(Ys,Is, Xs),
append(_, Ys, Is).
append("w", _, W), % or: "w" = [C], W = [C|_]
append(_, W, Ys).
Is it better readable? I think not.
The part with the [o,k] looks a bit unnatural to me, but it would be:
list_ret(Xs, Ys) :-
list_suspect(Xs, Ys).
list_ret(Xs, Ys) :-
\+ list_suspect(Xs,_),
Ys = "ok".
one liner, using append/2
suspect(L, S) :-
length(S, 5), append([S,_,S], L), memberchk(w, S) -> true ; S = [o,k].
edit as noted by false, the definition is buggy (lacks steadfastness ?): an amended rule
suspect(L, R) :-
length(S, 5), append([S,_,S], L), memberchk(w, S) -> S = R ; R = [o,k].

Prolog remove non-duplicates

I've been trying to write some code that takes a list of values, and removes all values which are only in the list once, the non-duplicates:
dbltaker([], []).
dbltaker([H | X], Y):-
\+mem(H, X),
dbltaker(X, Y).
dbltaker([H | X], [H | Y]):-
mem(H, X), !,
dbltaker(X, Y).
dbltaker([H | X], [H | Y]):-
mem(H, Y),
dbltaker(X, Y).
mem(H, [H | _]).
mem(H, [_ | T]):-
mem(H, T).
The trouble I've been having is that after I move a non-duplicate to the other list, it's duplicate is no longer a duplicate so isn't moved into the list. For example, the list [1, 1, 1, 2, 2, 3] gives [1, 1, 2] as the output, as the last one and two aren't considered duplicates as they're no longer members of their tails, and I can't check to see if they're members of the new list, as it's yet to be instantiated.
Is there a way around this?
Thanks.
I think the simpler way should be to should pass around to original list, to be able to check when an element is duplicate or not.
dbltaker(L, R) :- dbltaker(L, L, R).
dbltaker([], _L, []).
dbltaker([H|T], L, [H|R]) :- at_least_2(H, L), !, dbltaker(T, L, R).
dbltaker([_|T], L, R) :- dbltaker(T, L, R).
the service predicate at_least_2(H, L) can easily be implemented...
This is how I'd do it:
First, a check for list membership:
exists_in( A , [A|_] ) :- ! .
exists_in( A , [_|B] ) :- exists_in(A,B) .
Then a conditional add. If X is not contained in Y, add X to Y giving Z:
add_if_not_exists( X , Z , Z ) :- exists(X,T) , ! .
add_if_not_exists( X , Y , [X|Y] ) .
A worker predicate that does the hard work, using an accumulator (seeded to the empty list []) to build the set of distinct elements:
dedupe( [] , Z , Z ) . % if the source list is exhausted, we're done: the accumulator is the set of distinct list members.
dedupe( [X|Xs] , Y , Z ) :- % otherwise...
add_if_not_exists(X,Y,T) , % - add X to the accumulator if it's not already there.
dedupe(Xs,T,Z) % - and recurse down.
. % Easy!
And finally, the public interface predicate that simply invokes the worker predicate:
dedupe( Xs, Ys ) :- % dedupe a list
dedupe( Xs, [] , Ys ) % by invoking the helper predicate with the accumulator seeded with the empty set.
. %
Note: the worker predicate builds the deduped list in reverse order. If order is important, reversing a list is trivial:
rev( [] , [] ) .
rev( [X|Xs] , Rs ) :- rev( Xs , [X|Rs] ) .
Just modify the public interface to do the reversal:
dedupe1( Xs, Ys ) :- % dedupe a list
dedupe( Xs, [] , T ) , % by invoking the helper predicate with the accumulator seeded to the empty set.
rev(T,Ys) % and reversing the result.
. %

Prolog - Filter List

So I have this homework due tommorow. I have to filter every nth element of a list and return it as a list. So for example:
?- everyNth(3,[a,b,c,d,e,f],Rs).
Rs = [c,f].
My Idea was basically:
everynth(N, [X|Xs], L) :- everynth(N, [X|Xs], N, L).
everynth(N, [], C, L).
everynth(N, [X|Xs], 0, [X]) :- everynth(N, Xs, N, [X]).
everynth(N, [X|Xs], C, L) :- C1 is C -1,
everynth(N,Xs,C1,L).
But it does not work this way, because in the third row it tries to match X and the return X and the Count 0 the second time it goes there.
You are almost there. Check these modifications:
everynth(N, L, NL) :- everynth(N, L, N, NL).
everynth(_, [], _, []).
everynth(N, [X|Xs], 1, [X|NXs]) :- everynth(N, Xs, N, NXs).
everynth(N, [_|Xs], C, NXs) :- C1 is C-1, C1>0,
everynth(N,Xs,C1,NXs).
The first clause of everynth/4 is the termination of the recursion. It should give an empty list when there are no more items in the input list.
The second clause of everynth/4 deals with the nth item, it has to put the input item in the output list and keep processing the remaining items restarting your item counter.
And the third clause of everynth/4 deals with items which are not the nth element, so you have to skip the item, decrement the counter and continue with the remaining items.
everynth(_, _, [], R, R).
everynth(1, M, [X|Xs], Z, R) :- append(Z, [X], Z1), everynth(M, M, Xs, Z1, R).
everynth(N, M, [_|Xs], Z, R) :- N > 1, N1 is N - 1, everynth(N1, M, Xs, Z, R).
?- everynth(3, 3, [a,b,c,d,e,f], [], Rs).
Rs = [c, f] .

Split a list in half

I need to define divide so that List [1,2,3,4,5] divides into:
a = [1,2,3}
b = [4,5]
I'm getting an error that says "Arguments are not sufficiently instantiated", and I don't know enough about the language to figure out what my problem is, or if my design is even right. Any guidance would be appreciated.
So here's what I have so far:
append([],L2,L2).
append([H|T],L2,[H|L3]) :- append(T,L2,L3).
lengthIs([],N).
lengthIs([H|T],N) :- lengthIs(T,M), N is M+1.
divide([],[],[]).
divide([H|T],L2,L3) :-
( lengthIs(L2, M) < lengthIs(L1,N)/2
-> divide(T, append(L2, H, X), L3)
; divide(T, L2, append(L3,H,Y))
).
Let's give the predicate a more relational name: list_half_half/3
list_half_half(Xs, Ys, Zs) :-
length(Xs, N),
H is N - N // 2,
length(Ys, H),
append(Ys, Zs, Xs).
length/2 and append/3 are predefined in practically all recent Prologs.
This is GNU Prolog:
| ?- append(L,_,[a,b,c,d]), list_half_half(L,H1,H2).
H1 = []
H2 = []
L = [] ? ;
H1 = [a]
H2 = []
L = [a] ? ;
H1 = [a]
H2 = [b]
L = [a,b] ? ;
H1 = [a,b]
H2 = [c]
L = [a,b,c] ? ;
H1 = [a,b]
H2 = [c,d]
L = [a,b,c,d]
This is the most efficient solution conforming to your specification for most Prolog implementations:
divide(L, A, B) :-
divide1(L, L, A, B).
divide1([], L, [], L).
divide1([_|T], [H|L], [H|A], B) :-
divide2(T, L, A, B).
divide2([], L, [], L).
divide2([_|T], L, A, B) :-
divide1(T, L, A, B).
If you don't mind which elements go into the sublists as far as they are of similar length (as in the solution from Konstantin Weitz post), then you can use :
divide([], [], []).
divide([H|T], [H|A], B) :- divide(T, B, A).
append is a pre-defined predicate, so that might be the issue: http://en.wikibooks.org/wiki/Prolog/Lists#The_append_predicate
You also never defined 'N' in lengthIs - you need to set the empty list as 0, not N/
There's likely also a size function
The underscore tells Prolog we don't care about that bit in that predicate definition.
Something like this should work
divide(L1,L2,L3):- append(L2,L3,L1),
samesize(L2,L3).
divide(L1,L2,L3):- append(L2,L3,L1),
onebigger(L2,L3).
samesize(A,B):- size(A,N),
size(B,N).
onebigger(A,[_|T]):- size(A,N),
size(T,N).
size([],0).
size([H|T],N):- size(T,M+1).
Surely the effect of this code (lengthIs(L2, M) < lengthIs(L1,N)/2 -> ...) isn't what you expect: it doesn't compare numbers, but terms. You should write it this way:
lengthIs(L2, M), lengthIs(L1, N), M < N/2 -> ...
Another typo like mistake: the first clause of lengthIs/2 should read
lengthIs([],0).
No need to check sizes. Just do it like this:
div([],[],[]).
div([A],[A],[]).
div([A,B|T],[A|X],[B|Y]) :- div(T,X,Y).
Here's a sort of "rabbit and hare" approach.
divide(Xs,Ys,Zs) :-
divide(Xs,Xs,Ys,Zs).
divide(Ls,[],[],Ls).
divide([H|Ts],[_],[H],Ts).
divide([H|Ts],[_,_|Zs],[H|Us],Rs)
:- divide(Ts,Zs,Us,Rs).
The divide/4 predicate works but stripping both a single element and a double element from the initial list. By the time the second argument gets to the empty list or a list of one element then we are effectively halfway through the list passed as the first argument.
It's effectively O(n/2) complexity.
Here's a sample output:
?- divide([a,b,c,d,e,f,g,h],X,Y).
X = [a, b, c, d],
Y = [e, f, g, h] .
?- divide([a,b,c,d,e,f,g],X,Y).
X = [a, b, c, d],
Y = [e, f, g] .
Another answer,
uses Backtracking a lot, isn't very performant, though.
append and length are assumed to be predefined:
divide(A,B,C):-
append(B,C,A),
length(B,B_Length),
length(C,C_Length),
(B_Length = C_Length;
B_Length =:= C_Length +1).
Oh, sorry, just have seen that this is sort of a rephrasing of the answer from Philip Whitehouse.
This is how I did it. Almost no built-ins:
split_list_in_half( Xs , H , T ) :-
list_length( X , L ) ,
LL = L - (L // 2) ,
take_first( Xs , LL , H , T ) ,
.
list_length( L , N ) :-
list_length( L , 0 , N )
.
list_length( [] , N , N ).
list_length( [X|Xs] , T , N ) :-
T1 is T+1 ,
list_length( Xs , T1 , N )
.
take_first( Xs , N , Pfx , Sfx ) :-
take_first( Xs , N , [] , P1 , Sfx ) ,
reverse( P1 , Pfx )
.
take_first( [] , _ , H , H , [] ).
take_first( [X|Xs] , 0 , H , H , [X|Xs] ).
take_first( [X|Xs] , N , H1 , H , T ) :-
N > 0 ,
N1 = N-1 ,
take_first( Xs , N1 , [X|H1] , H , T )
.
Improved head-and-tail iteration, guarding against infinity:
split_list_half([A,B|T], Half1, Half2) :-
split_list_half_([A,B|T], [A,B|T], Half1, Half2, Half2).
split_list_half_([], H2, [], _, H2).
% H2D prevents infinity with: split_list_half(L, H1, [c, d]).
split_list_half_([_|T], [H|Sgl], H1, H2D, H2) :-
split_list_half_dbl_(T, H, Sgl, H1, H2D, H2).
split_list_half_dbl_([], H, H2, [H], _, H2).
split_list_half_dbl_([_|T], H, Sgl, [H|H1], [_|H2D], H2) :-
split_list_half_(T, Sgl, H1, H2D, H2).
Results in swi-prolog:
?- split_list_half([a,b,c,d], H1, H2).
H1 = [a, b],
H2 = [c, d].
?- split_list_half([a,b,c,d,e], H1, H2).
H1 = [a, b, c],
H2 = [d, e].
?- split_list_half(LF, H1, [d, e]).
LF = [_A, _B, d, e],
H1 = [_A, _B] ;
LF = [_A, _B, _C, d, e],
H1 = [_A, _B, _C] ;
false.