这个Prolog代码如何真正起作用 - 随机播放两个列表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了这个Prolog代码如何真正起作用 - 随机播放两个列表相关的知识,希望对你有一定的参考价值。

我有以下代码,工作,洗牌两个列表:

shuffle([], [], []).
shuffle([X|Xs], Ys, [X|Zs]):-
          shuffle(Xs, Ys, Zs).
shuffle(Xs, [Y|Ys], [Y|Zs]):-
          shuffle(Xs, Ys, Zs).

我分别理解每个部分。第一个子句接收两个列表,一个用X作为头,Xs是尾。在结果中我们只“拿”第一个列表的头部。与第二个条款相同 - 我们不接受Xs的结果,只有Y的头。

Prolog以递归方式分离列表,然后将它们统一起来。

这里我不明白它是如何工作的?结束“取出”所有Xs后,它只是“移动”到第二个条款,采取Ys?什么触发Prolog做到这一点?

谢谢。

答案

当你试图在Prolog中证明一个目标时,例如:shuffle([a],[c],L). Prolog所做的就是在数据库中搜索以找到与谓词shuffle一样多的规则。

在这种情况下,第二个和第三个规则都会出现,因此您有两个选项 - 在Prolog中调用的选择点:

第一选择点:我们检查第二个规则:shuffle([X|Xs],Ys,[X|Zs]):- shuffle(Xs,Ys,Zs).并在我们的目标中应用它我们得到[X|Xs] = [a](所以X = a, Xs = []),Ys = [c]L[a|Zs]形式,最后递归shuffle([],[c],Zs)被称为。这个目标现在只匹配第三个规则,我们得到Zs = [c|Zs']并再次递归shuffle([],[],Zs')被称为现在只有第一个规则匹配,我们得到Zs' = []。所以从第一个案例中我们得到了Zs = [a,c]。现在我们又留下了另一个案例:

第二选择点:我们检查第三条规则:shuffle(Xs,[Y|Ys],[Y|Zs]):- shuffle(Xs,Ys,Zs).并将其应用于我们的目标中我们得到Xs = [a], [Y|Ys] = [c](所以Y = c, Ys = []),而L的形式为[c|Zs],最后递归地称为shuffle([a],[],Zs)。这个目标现在只匹配第二个规则,我们得到Zs = [a|Zs']并再次递归shuffle([],[],Zs')被称为现在只有第一个规则匹配,我们得到Zs' = []。所以从第二个案例中我们得到了Zs = [c,a]

最后我们得到了两个解决方案。正如您所看到的,Prolog对选择点进行了深度优先分析,因为它找到了第一个选择点并检查了它并继续进行了第三个选择点,依此类推。这里显而易见的问题是你可以想象两个元素列表的选择点的数量,例如shuffle([a,b],[c,d],L)?这将是四个选择点,对于Xs,Ys的一般情况,选择点太多了。

另一答案

避免所有X和Y和Z部分,我们可以对工作代码说些什么:

  1. 你从像shuffle([1,2],[a,b],L).这样的查询开始,Prolog试图通过解决三个shuffle规则来解决它。
  2. 一个shuffle规则可以自己解决,但仅限于空列表,另外两个依赖于解决另一个shuffle规则的情况。
  3. 无论找到什么解决方案都必须去shuffle -> shuffle -> [shuffle....] -> empty lists。它必须。如果它根本无法匹配任何shuffle,它将回答“false”,你的代码将无效。如果它在洗牌之间永远反弹,它将无限循环并且没有给出答案,你的代码也行不通。它确实有效,所以它必须从一开始就通过shuffle的组合链接到空列表。

Prolog将尝试从规则的顶部解决:

From the top:

A) shuffle([1,2],[a,b],L).  -no->  shuffle([],[],[]).
B) shuffle([1,2],[a,b],L).  -??->  shuffle([X|Xs],Ys,[X|Zs]):- shuffle(Xs,Ys,Zs).
B) shuffle([1,2],[a,b],L).  -??->  shuffle([X=1|Xs=[2]],Ys=[a,b],[X=1|Zs=??]) :- shuffle(Xs=[2],Ys=[a,b],Zs).

% A) fails as [1,2] does not match with []
% B) partially binds but is missing Zs. Solving to try and find the Zs is now:

shuffle(Xs=[2],Ys=[a,b],Zs).



From the top:

A) shuffle([2],[a,b],Zs).  -no->  shuffle([],[],[]).
B) shuffle([2],[a,b],Zs).  -??->  shuffle([X|Xs],Ys,[X|Zs]):- shuffle(Xs,Ys,Zs).
B) shuffle([2],[a,b],Zs).  -??->  shuffle([X=2|Xs=[]],Ys=[a,b],[X=2|Zs=??]):- shuffle(Xs,Ys,Zs).

% A) fails as [2] does not match with []
% B) partially binds but is missing Zs. Solving to try and find the Zs is now:

shuffle(Xs=[],Ys=[a,b],Zs).



From the top:

A) shuffle([],[a,b],Zs).  -no->  shuffle([],[],[]).
B) shuffle([],[a,b],Zs).  -no->  shuffle([X|Xs],Ys,[X|Zs]):- shuffle(Xs,Ys,Zs).
C) shuffle([],[a,b],Zs).  -??->  shuffle(Xs,[Y|Ys],[Y|Zs]):- shuffle(Xs,Ys,Zs).
C) shuffle([],[a,b],Zs).  -??->  shuffle(Xs=[],[Y=a|Ys=[b]],[Y=a|Zs=??]):- shuffle(Xs,Ys,Zs).

% A) fails as [a,b] does not match with the second []
% B) fails as [] does not match with [X|Xs]
% C) partially binds but is missing Zs. Solving to try and find the Zs is now:

shuffle([],[b],Zs).



From the top:

A) shuffle([],[b],Zs).  -no->  shuffle([],[],[]).
B) shuffle([],[b],Zs).  -no->  shuffle([X|Xs],Ys,[X|Zs]):- shuffle(Xs,Ys,Zs).
C) shuffle([],[b],Zs).  -??->  shuffle(Xs,[Y|Ys],[Y|Zs]):- shuffle(Xs,Ys,Zs).
C) shuffle([],[b],Zs).  -??->  shuffle(Xs=[],[Y=b|Ys=[]],[Y=b|Zs=??]):- shuffle(Xs,Ys,Zs).

% A) fails as [b] does not match with the second []
% B) fails as [] does not match with [X|Xs]
% C) partially binds but is missing Zs. Solving to try and find the Zs is now:

shuffle([],[],Zs).



From the top:

A) shuffle([],[],Zs).  -no->  shuffle([],[],[]).

% A) succeeds. Zs can be []

这是一个完整的链,从原点,通过四个shuffle,到空列表。在这个链中,Zs已被构建为[1|?]然后[1|[2|?]]然后[1|[2|[a|?]]]然后[1|[2|[a|[b|?]]]]然后[1|[2|[a|[b|[]]]]]这是完整的,没有遗漏任何东西。这与第一个结果的L输入结合。

它已经通过洗牌B B C C


但搜索空间并未耗尽,可能会有更多答案。如果你要求它们,它会将链条展开回到一个可能采取不同路径的地方。而不是解决shuffle([X|Xs]..它可以跳过那一个,而是潜入shuffle(Xs而不是。

具有大量值的两个shuffle谓词共同构成一个反弹模式,该模式以三个空列表情况终止:

[1,2],[a,b],Unknown
        \
         \
          \ ? shuffle shuffle shuffle
          /
         /
         \
      [],[],[]

一条逻辑连接链是B B C C A。另一个链是B C B C A,导致下一个答案L=[1,a,2,b]

[1,2],[a,b],Unknown
       /   \       
      /     \
      \      \ B C B A
B B C C\     /
       |    /
       |    \
      [],[],[]

一旦它一直回溯,在每个选择中交换了另一个的shuffle并沿着链条到空列表,它将找到6条路径,6种方式通过shuffle反弹。

随着列表更长,链条变长。当它开始回溯链条时,撤消其寻找其他方法的步骤,其中有更多。更多的选择点,因此它将找到更多的解决方案 - 与输入的长度成比例。

以上是关于这个Prolog代码如何真正起作用 - 随机播放两个列表的主要内容,如果未能解决你的问题,请参考以下文章

应用播放背景音频不起作用

HAVING 子句如何真正起作用?

如何不断更新我正在使用 JS 播放的这个 mp3 文件的持续时间?进度条不起作用

姜戈。 Q() 如何真正起作用?

再次播放按钮不起作用

jquery的promise方法是如何真正起作用的?