【问题标题】:Prolog unpacking lists predicateProlog 解包列表谓词
【发布时间】:2017-09-29 02:57:50
【问题描述】:

我试图创造一些像这样工作的东西:

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

【问题讨论】:

  • 你对[[],[1],[2]]有什么期望?
  • 这是做什么的?它应该做什么?你有什么问题?...
  • @false 实际上从来没有考虑过那个输入 :) 因为我正在处理通常里面有东西的列表。
  • @Boris 所做的是将一个列表解包到另一个列表中,但只保留一个元素列表,因此不是列表列表而是具有非列表元素的列表,它只保留单元素列表,我看到有点混乱。
  • 但是为什么你有三个参数呢?两个论点应该就够了我有感觉....

标签: prolog


【解决方案1】:

你的意思可能是:

unpacking([], []).
unpacking([[E]|T], [E|L]) :-
   unpacking(T, L).
unpacking([[]|T], L) :-
   unpacking(T, L).
unpacking([[_,_|_]|T], L) :-
   unpacking(T, L).

有更简洁的方法来编写这个 - 而且也更有效。

【讨论】:

  • 是的,谢谢!但是你能解释一下代码吗?
  • 这是列表头部的模式匹配 - 元素是 [E][][ _, _ |_ ]。在所有情况下,您都可以通过对尾部 T 的递归获得剩余元素 L。在单元素情况下,E 被添加到 L 之前,而在其他情况下,L 本身就足够了。
  • unpacking([[,_|]|T, L) 我认为是一个错字。
  • 谢谢!你的答案在哪里?
【解决方案2】:

这个呢:

%?-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 = [].

【讨论】:

  • tpartition 这个名字有点误导,因为分区通常是 x -> [x] -> [x] -> [x]
  • 你有什么建议? rel_list_fillers_segments 怎么样?
  • partition'n concat Haskeller 会说。
  • 我非常喜欢这个提议背后的想法,为此 +s(0)。不幸的是,由于使用了长度/2,查询?- unpacking([[1],[2,3],[4],[_,_|_]],U). 循环,一遍又一遍地产生解决方案U = [1, 4]。相比之下,接受的版本在产生唯一解决方案后留下了不必要的选择点,但在点击 ; 后终止。
  • 是的,完全正确。不管你用什么替换[_,_|_] 中的下划线,它肯定不能成为一个包含单个元素的列表。因此,无论如何它都不在列表中,迭代可能性毫无意义。但是,我的想法是一样的,到目前为止,我还没有想出一个确定性的解决方案来终止这种情况。关于我提交和遗憾的漂亮 peano 算术,请感觉 s(X)'ed ;-)
【解决方案3】:

基于@coder的解决方案,我自己尝试使用if_和DCGs:

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.

编辑:我改进了解决方案并尝试使用参数索引。根据SWI Manual,如果空列表[] 和非空列表[_|_] 之间存在大小写区别,则会发生索引。我重写了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].

仍然是确定性的。我没有在其他 Prologs 中尝试过这个解决方案,它可能缺少索引,但对于 SWI 来说,这是一个解决方案。

更新:显然 GNU Prolog 不会在循环列表上进行这种索引和溢出:

| ?- Xs = [[] | Xs], unpack(Xs,Ys).

Fatal Error: global stack overflow (size: 32770 Kb, reached: 32768 Kb, environment variable used: GLOBALSZ)

【讨论】:

  • 我不会称之为完美,但至少应该是完整的。根据Vs 的实例化,我仍然对两种实现之间的选择不满意。
  • unpack([[X|Xs]], []). 错误地失败,而Xs = [_|_], unpack([[X|Xs]], []). 按预期成功。你为什么要使用不纯的构造?切边?
  • 我找到了一个解决方案,但我不确定它对 SWI 的具体程度(它依赖于 [][_|_] 参数的索引)。你怎么看?
  • one_element 最好称为 one_element_t 以坚持最后一个 arg 是真值。
  • 使用set_prolog_flag(double_quotes, chars),目标unpack([[a,b,c],[a],[b],[c,d]],Items). 缩小为unpack(["abc","a","b","cd"],Items).。而help("append") 现在写成help(append)
【解决方案4】:

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

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

【讨论】:

  • one_element([_|L], false), L = [_]. 失败但L = [_], one_element([_|L], false). 成功。
  • @false,但要解决这个问题,我认为解包谓词不是确定性的,因为我们必须在 one_element/2 中留下一些选择点??
  • 当然会导致不一致!以?- unpacking([Xss],[]). 为例,它以Xss = [_,_|_] 失败。
  • 先正确,再考虑其余部分。
  • 正确性 OK,现在开始提高效率!最好是干净效率。
【解决方案5】:

一种方法是使用 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).

【讨论】:

  • unpacking([[E]],[1]), E = 2. 错误地成功。
  • unpacking(non_list, []). 也成功了。
  • unpacking([Xss],[]). 错误地失败了,尽管Xss=[], unpacking([Xss],[]). 成功了。
  • unpacking([Xs],Xs).不完整:应该有两个答案/解决方案:Xs = [_A]Xs = []
  • @Bl4ckCoding:findall/3 是一个非常低级的工具,不能很好地与纯代码混合。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多