Prolog解包列出谓词

时间:2017-05-01 17:24:44

标签: prolog

嘿伙计们,所以我试着创造一些像这样的东西:

?- 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开始的,所以需要从我的错误中吸取教训:)

5 个答案:

答案 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).

这基于Most general higher-order constraint describing a sequence of integers ordered with respect to a relation

*更新*

您可以更改为

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).