Prolog解包列出谓词

Bl4*_*ing 11 prolog

嘿伙计,所以我试图创造一些像这样的工作:

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

fal*_*lse 6

你可能意味着:

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)

有更简洁的方法来写这个 - 而且效率也更高.


use*_*815 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).
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)

  • 对,就是这样.无论你用什么代替`[_,_ | _]`中的下划线,它肯定不能成为一个单一元素的列表.因此,无论如何它都不在列表中,迭代可能性毫无意义.但是,我正在思考同样的问题,并且无法提出一个确定性的解决方案,该解决方案到目前为止已经终止了.关于我提交和后悔的精彩peano算法,请感觉s(X)'ed而不是;-) (3认同)
  • 我非常喜欢这个提案背后的想法,+ s(0).不幸的是,由于使用了长度/ 2,查询`? - 解包([[1],[2,3],[4],[_,_ | _]],U).`循环,产生解决方案`U = [1,4]`一遍又一遍.相比之下,接受的版本在产生唯一的解决方案后会留下一个不必要的选择点,但在点击`;`后终止. (2认同)

lam*_*y.x 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).
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)


cod*_*der 5

经过一番思考,这是我的实现使用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)

但这留下了一些选择点......

  • `one_element([_ | L],false),L = [_].`失败但是`L = [_],one_element([_ | L],false).`成功. (2认同)