嘿伙计们,所以我试着创造一些像这样的东西:
?- unpacking([[1], [1,2], [3]], Lst1, NewLst).
NewLst=[1,3]
我是这样写的:
unpacking([], Lst1, Lst1).
unpacking([[H]|T], Lst1, NewLst):-
append([H], Lst2),
unpacking(T, Lst2, NewLst).
unpacking([_|T], Lst1, NewLst):-
unpacking(T, Lst1, NewLst).
我知道我做错了什么,但是,我是从Prolog开始的,所以需要从我的错误中吸取教训:)
答案 0 :(得分:6)
你可能意味着:
unpacking([], []).
unpacking([[E]|T], [E|L]) :-
unpacking(T, L).
unpacking([[]|T], L) :-
unpacking(T, L).
unpacking([[_,_|_]|T], L) :-
unpacking(T, L).
有更简洁的方法来写这个 - 而且效率更高。
答案 1 :(得分:6)
这个怎么样:
%?-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).
*更新*
您可以更改为
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).
,并提供:
?-unpacking([[1],[2,3],[4],[_,_|_]],U).
U= [1,4].
但:
?-unpacking([X],Xs).
X = Xs, Xs = [].
答案 2 :(得分:6)
经过一番思考,这是我使用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).
一些测试用例:
?- 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 = [].
<强>更新强>
要修复我们可以定义的注释中引用@false的情况:
one_element([],false).
one_element([_],true).
one_element([_,_|_],false).
但这留下了一些选择点......
答案 3 :(得分:6)
根据@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).
我只尝试了大约30秒,但查询:
?- Xs = [[] | Xs], unpack(Xs,Ys).
?- Xs = [[_] | Xs], unpack(Xs,Ys).
?- Xs = [[_, _ | _] | Xs], unpack(Xs,Ys).
堆栈溢出没有停止。在我看来,关键的一个应该是最后一个查询,但显然,SWI Prolog设法优化:
?- L = [_,_|_], one_element(L,T).
L = [_3162, _3168|_3170],
T = false.
编辑:我改进了解决方案并为其提供了参数索引。根据{{3}},如果空列表[]
和非空列表[_|_]
之间存在完全不同的情况,则会发生索引。我重新编写了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 = [].
但
?- unpack([[a,b,c],[a],[b],[c,d]],Items).
Items = [a, b].
仍然是确定性的。我没有在其他Prolog中尝试过这个解决方案,这可能会错过索引,但对于SWI来说,这似乎是一个解决方案。
更新:显然GNU Prolog不会在循环列表上执行此类索引和溢出:
| ?- Xs = [[] | Xs], unpack(Xs,Ys).
Fatal Error: global stack overflow (size: 32770 Kb, reached: 32768 Kb, environment variable used: GLOBALSZ)
答案 4 :(得分:1)
实现这一目标的一种方法是使用findall我不认为它是赏金的用途;)
unpacking(Lists,L1):-
findall(I,(member(M,Lists),length(M,1),M=[I]),L1).
or
unpacking2(Lists,L1):-
findall(I,member([I],Lists),L1).