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).
0 comments:
Post a Comment