嘿伙计,所以我试图创造一些像这样的工作:
?- unpacking([[1], [1,2], [3]], Lst1, NewLst).
NewLst=[1,3]
Run Code Online (Sandbox Code Playgroud)
我这样写的:
unpacking([], Lst1, Lst1).
unpacking([[H]|T], Lst1, NewLst):-
append([H], Lst2),
unpacking(T, Lst2, NewLst).
unpacking([_|T], Lst1, NewLst):-
unpacking(T, Lst1, NewLst).
Run Code Online (Sandbox Code Playgroud)
我知道我做错了什么,但是,我是在Prolog开始所以,需要从我的错误中吸取教训:)
你可能意味着:
unpacking([], []).
unpacking([[E]|T], [E|L]) :-
unpacking(T, L).
unpacking([[]|T], L) :-
unpacking(T, L).
unpacking([[_,_|_]|T], L) :-
unpacking(T, L).
Run Code Online (Sandbox Code Playgroud)
有更简洁的方法来写这个 - 而且效率也更高.
那这个呢 :
%?-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).
Run Code Online (Sandbox Code Playgroud)
*更新*
你可以改为
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).
Run Code Online (Sandbox Code Playgroud)
赠送:
?-unpacking([[1],[2,3],[4],[_,_|_]],U).
U= [1,4].
Run Code Online (Sandbox Code Playgroud)
但:
?-unpacking([X],Xs).
X = Xs, Xs = [].
Run Code Online (Sandbox Code Playgroud)
根据@coder的解决方案,我自己尝试使用if_和DCG:
one_element_([], true).
one_element_([_|_],false).
one_element([], false).
one_element([_|Xs], T) :-
one_element_(Xs, T).
f([]) -->
[].
f([X|Xs]) -->
{ if_(one_element(X), Y=X, Y=[]) },
Y,
f(Xs).
unpack(Xs,Ys) :-
phrase(f(Xs),Ys).
Run Code Online (Sandbox Code Playgroud)
我只尝试了大约30秒,但查询:
?- Xs = [[] | Xs], unpack(Xs,Ys).
?- Xs = [[_] | Xs], unpack(Xs,Ys).
?- Xs = [[_, _ | _] | Xs], unpack(Xs,Ys).
Run Code Online (Sandbox Code Playgroud)
没有因堆栈溢出而停止.在我看来,关键的应该是最后一个查询,但显然,SWI Prolog设法优化:
?- L = [_,_|_], one_element(L,T).
L = [_3162, _3168|_3170],
T = false.
Run Code Online (Sandbox Code Playgroud)
编辑:我改进了解决方案,并给出了一个带参数索引的镜头.根据SWI手册,如果空列表[]和非空列表之间存在完全不同的情况,则会发生索引[_|_].我重写了one_element这样,它确实如此,并用辅助谓词重复了这个技巧one_element_.现在这又one_element是纯粹的,我们不再失去解决方案了:
?- unpack([A,B],[]).
A = [_5574, _5580|_5582],
B = [_5628, _5634|_5636] ;
A = [_5574, _5580|_5582],
B = [] ;
A = [],
B = [_5616, _5622|_5624] ;
A = B, B = [].
Run Code Online (Sandbox Code Playgroud)
但
?- unpack([[a,b,c],[a],[b],[c,d]],Items).
Items = [a, b].
Run Code Online (Sandbox Code Playgroud)
仍然是确定性的.我没有在其他Prolog中试过这个解决方案,这可能会错过索引,但对于SWI来说,这似乎是一个解决方案.
更新:显然GNU Prolog不会在循环列表上执行此类索引和溢出:
| ?- Xs = [[] | Xs], unpack(Xs,Ys).
Fatal Error: global stack overflow (size: 32770 Kb, reached: 32768 Kb, environment variable used: GLOBALSZ)
Run Code Online (Sandbox Code Playgroud)
经过一番思考,这是我的实现使用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).
Run Code Online (Sandbox Code Playgroud)
一些测试用例:
?- 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 = [].
Run Code Online (Sandbox Code Playgroud)
更新
要修复我们可以定义的注释中引用的@false的情况:
one_element([],false).
one_element([_],true).
one_element([_,_|_],false).
Run Code Online (Sandbox Code Playgroud)
但这留下了一些选择点......