Thursday, May 11, 2017

Prolog unpacking lists predicate

Leave a Comment

Hey guys so I tried to create something what would work like this:

?- unpacking([[1], [1,2], [3]], Lst1, NewLst). NewLst=[1,3] 

I wrote it like this:

unpacking([], Lst1, Lst1). unpacking([[H]|T], Lst1, NewLst):-     append([H], Lst2),     unpacking(T, Lst2, NewLst). unpacking([_|T], Lst1, NewLst):-     unpacking(T, Lst1, NewLst). 

and I know that I am doing something wrong, but yeh, I'm starting in Prolog so, need to learn from my mistakes :)

5 Answers

Answers 1

You probably meant:

unpacking([], []). unpacking([[E]|T], [E|L]) :-    unpacking(T, L). unpacking([[]|T], L) :-    unpacking(T, L). unpacking([[_,_|_]|T], L) :-    unpacking(T, L). 

There are more concise ways to write this - and more efficient, too.

Answers 2

What about this :

%?-unpacking([[a,b,c],[a],[b],[c,d]],Items). unpacking(Lists,Items):-  my_tpartition(length_t(1),Lists,Items,Falses).  my_tpartition(P_2,List,Ts,Fs) :- my_tpartition_ts_fs_(List,Ts,Fs,P_2).  my_tpartition_ts_fs_([],[],[],_). my_tpartition_ts_fs_([X|Xs0],Ts,Fs,P_2) :-  if_(call(P_2,X), (X=[NX],Ts = [NX|Ts0], Fs = Fs0),                 (Ts = Ts0,     Fs = [X|Fs0])), my_tpartition_ts_fs_(Xs0,Ts0,Fs0,P_2).  length_t(X,Y,T):-  length(Y,L1),  =(X,L1,T). 

This is based on Most general higher-order constraint describing a sequence of integers ordered with respect to a relation

* Update*

You could change to

length_t(X,Y,T):-  L1 #=< X,  fd_length(Y,L1),  =(X,L1,T),!.  length_t(_X,_Y,false).  fd_length(L, N) :-  N #>= 0,  fd_length(L, N, 0).  fd_length([], N, N0) :-  N #= N0. fd_length([_|L], N, N0) :-  N1 is N0+1,  N #>= N1,  fd_length(L, N, N1). 

giving:

?-unpacking([[1],[2,3],[4],[_,_|_]],U). U= [1,4]. 

but:

?-unpacking([X],Xs). X = Xs, Xs = []. 

Answers 3

After some thought, here is my implementation using if_/3:

unpacking(L,L1):-if_( =(L,[]), L1=[], unpack(L,L1)).  unpack([H|T],L):-if_(one_element(H), (H = [X],L=[X|T1],unpacking(T,T1)), unpacking(T,L)).  one_element(X, T) :-    (  var(X) ->(T=true,X=[_]; T=false,X=[])     ;  X = [_] -> T = true     ;  X \= [_] -> T = false). 

Some testcases:

?- unpacking([Xss],[]).  Xss = [].  ?- unpacking([[1],[2,3],[4],[_,_|_]],U). U = [1, 4].  ?- unpacking([[1],[2,3],[4]],U). U = [1, 4].  ?- unpacking([[E]],[1]), E = 2. false.  ?- unpacking(non_list, []). false.  ?- unpacking([Xs],Xs). Xs = [_G6221] ; Xs = []. 

UPDATE
To fix the case that @false referred in the comment we could define:

one_element([],false). one_element([_],true). one_element([_,_|_],false). 

But this leaves some choice points...

Answers 4

Based on @coder's solution, I made my own attempt based on if_ and DCGs:

one_element([_],true) :-     !. one_element([_,_|_],false). one_element([],false).   f([]) -->     []. f([X|Xs]) -->     { if_(one_element(X), Y=X, Y=[]) },     Y,     f(Xs).  unpack(Xs,Ys) :-     phrase(f(Xs),Ys). 

I only tried for about 30s, but the queries:

?- Xs = [[] | Xs], unpack(Xs,Ys). ?- Xs = [[_] | Xs], unpack(Xs,Ys). ?- Xs = [[_, _ | _] | Xs], unpack(Xs,Ys). 

didn't stop with a stack overflow. In my opinion, the critical one should be the last query, but apparently, SWI Prolog manages to optimize:

?- L = [_,_|_], one_element(L,T). L = [_3162, _3168|_3170], T = false. 

Edit: Oh no, the cut is not green:

?- unpack([A,B],Ys), Ys = []. false. 

This solution is incomplete!

Answers 5

One way to do it is with a findall I dont think its what the bounty is for though ;)

unpacking(Lists,L1):-    findall(I,(member(M,Lists),length(M,1),M=[I]),L1).  or   unpacking2(Lists,L1):-    findall(I,member([I],Lists),L1). 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment