List 使用prolog再添加两个引用

List 使用prolog再添加两个引用,list,prolog,prolog-dif,logical-purity,prolog-toplevel,List,Prolog,Prolog Dif,Logical Purity,Prolog Toplevel,我有一个列表[a,b,a,a,a,c,c] 我需要为每个元素再添加两个引用 最终结果应如下所示: [a, a, a, b, b, b, a, a, a, a, a, c, c, c, c] % Case 1 dbl([],[]). % Case 2 dbl([X],[X,X,X]). % Case 3 dbl([X,X|Xs], [X|Ys]) :- % [...] recursion skipping the leading X % Case 4 dbl([X,Y|Xs], [X,X,

我有一个列表
[a,b,a,a,a,c,c]
我需要为每个元素再添加两个引用

最终结果应如下所示:

[a, a, a, b, b, b, a, a, a, a, a, c, c, c, c]
% Case 1
dbl([],[]).
% Case 2
dbl([X],[X,X,X]).
% Case 3
dbl([X,X|Xs], [X|Ys]) :-
   % [...] recursion skipping the leading X
% Case 4
dbl([X,Y|Xs], [X,X,X|Ys]) :-
   dif(X,Y),
   % [...] we inserted the copies, so recursion on [Y|Xs] and Ys
如果列表中有一个项目与下一个项目相同,那么它会一直运行,直到有一个新项目,当它找到新项目时,它会添加上一个项目的两个匹配项,然后继续

这是到目前为止我的代码,但我不知道如何添加两个

dbl([], []).
dbl([X], [X,X]).
dbl([H|T], [H,H|T], [H,H|R]) :- dbl(T, R).

您的代码看起来有点奇怪,因为最后一条规则包含三个参数。您只调用二进制版本,因此任何递归都不会尝试派生它

您已经有了一个好主意,可以查看列表中元素发生变化的部分。因此有4种情况:

1) 你的名单是空的。 2) 你只有一个元素。 3) 您的列表以两个相等的元素开始。 4) 您的列表以两个不同的元素开始

案例1未指定,因此您可能需要为此找到一个合理的选择。案例2在某种程度上类似于案例4,因为列表的结尾可以被视为元素中的一个更改,您需要附加两个副本,但之后就完成了。案例3非常简单,我们可以只保留元素并在其余元素上递归。案例4是您需要再次插入两份副本的情况

这意味着您的代码将如下所示:

[a, a, a, b, b, b, a, a, a, a, a, c, c, c, c]
% Case 1
dbl([],[]).
% Case 2
dbl([X],[X,X,X]).
% Case 3
dbl([X,X|Xs], [X|Ys]) :-
   % [...] recursion skipping the leading X
% Case 4
dbl([X,Y|Xs], [X,X,X|Ys]) :-
   dif(X,Y),
   % [...] we inserted the copies, so recursion on [Y|Xs] and Ys
案例3应该很容易完成,我们只需从两个列表中删除第一个X,然后在dbl上递归([X | Xs],Ys)。请注意,我们通过两次写入同一变量隐式地使前两个元素相等(即,我们统一了它们)

如果你看案例4的开头,你可以直接模仿你描述的模式:假设列表以X开始,然后Y,它们是不同的(dif(X,Y)),X被重复3次而不是仅仅复制,然后我们继续从Y:dbl([Y | Xs],Ys]开始的递归

那么让我们试试谓词:

?- dbl([a,b,a,a,a,c,c],[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]).
true ;
false.
我们的测试用例被接受(true),并且我们没有找到多个解决方案(false)。 让我们看看是否找到了错误的解决方案:

?- dif(Xs,[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]), dbl([a,b,a,a,a,c,c],Xs).
false.
?- dbl(X,[a,a,a,b,b]).
false.
不,那也很好。如果列表中有变量,会发生什么

?- dbl([a,X,a],Ys).
X = a,
Ys = [a, a, a, a, a] ;
Ys = [a, a, a, X, X, X, a, a, a],
dif(X, a),
dif(X, a) ;
false.
X=a,则Ys为5 as的单次运行;或者X不等于a,那么我们需要在所有三次运行中追加副本。看起来也不错。(*)

现在让我们看看,如果我们只指定解决方案会发生什么:

?- dif(Xs,[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]), dbl([a,b,a,a,a,c,c],Xs).
false.
?- dbl(X,[a,a,a,b,b]).
false.
对,一个只运行两个bs的列表不可能是我们规范的结果。因此,让我们尝试添加一个:

?- dbl(X,[a,a,a,b,b,b]).
X = [a, b] ;
false.
万岁,成功了!作为最后一个测试,让我们看看如果我们用两个变量调用谓词会发生什么:

?- dbl(Xs,Ys).
Xs = Ys, Ys = [] ;
Xs = [_G15],
Ys = [_G15, _G15, _G15] ;
Xs = [_G15, _G15],
Ys = [_G15, _G15, _G15, _G15] ;
Xs = [_G15, _G15, _G15],
Ys = [_G15, _G15, _G15, _G15, _G15] ;
Xs = [_G15, _G15, _G15, _G15],
Ys = [_G15, _G15, _G15, _G15, _G15, _G15] ;
[...]
看起来我们得到了正确的答案,但我们只看到了一次运行的案例。这是prolog搜索策略的结果(我在这里不解释)。但是,如果我们在生成较长的列表之前先查看较短的列表,我们可以看到所有的解决方案:

 ?- length(Xs,_), dbl(Xs,Ys).
Xs = Ys, Ys = [] ;
Xs = [_G16],
Ys = [_G16, _G16, _G16] ;
Xs = [_G16, _G16],
Ys = [_G16, _G16, _G16, _G16] ;
Xs = [_G86, _G89],
Ys = [_G86, _G86, _G86, _G89, _G89, _G89],
dif(_G86, _G89) ;
Xs = [_G16, _G16, _G16],
Ys = [_G16, _G16, _G16, _G16, _G16] ;
Xs = [_G188, _G188, _G194],
Ys = [_G188, _G188, _G188, _G188, _G194, _G194, _G194],
dif(_G188, _G194) ;
[...]
因此,我们似乎有一个工作谓词(**),假设您填写了文本中缺少的目标:)

(*)这里有一句话:这个案例之所以有效,是因为我们使用的是dif。通常遇到的第一个相等谓词是=、==及其各自的否定\=和\==。=表示可统一性(替换参数s.t中的变量。变量变为相等),而==表示语法相等(术语完全相等)。例如:

这意味着,如果我们用a代替X,我们可以使f(X)等于f(a)。这意味着,如果我们问它们是否不能相等(\=),我们会得到错误的答案。另一方面,这两个项不相等,因此==返回false,其否定\==返回true

这也意味着X\==Y始终为真,因此我们不能在代码中使用\==。与此相反,dif等待直到它能够决定其参数是否相等。如果在找到答案后仍未决定,则打印“dif(X,a)”语句

(**)最后一句话:这里还有一个if-then-else构造(test->goals\u if\u true;goals\u if\u false)的解决方案,它合并了案例3和案例4。由于我更喜欢这个解决方案,您可能需要自己研究另一个版本

dbl([X,Y|T], [X,X,X|R]) :- X \= Y, !, dbl([Y|T], R).
dbl([H|T], R) :-
        T = []
    ->  R = [H,H,H]
    ;   R = [H|Q], dbl(T, Q).
第一个子句处理基本需求,添加了两个关于顺序更改的元素。 第二个将列表终止处理为序列更改,否则将执行纯拷贝。

TL;DR: 从陈述的角度来看,这是完美的。 它的确定性可以在不牺牲的情况下得到改善


代码变体#0:@lambda.xy.x的代码

下面是我们要改进的代码:

dbl0([], []). dbl0([X], [X,X,X]). dbl0([X,X|Xs], [X|Ys]) :- dbl0([X|Xs], Ys). dbl0([X,Y|Xs], [X,X,X|Ys]) :- dif(X, Y), dbl0([Y|Xs], Ys). 更好?有点,但确定性可能更好

代码变体#2:索引

为了让Prolog看到
dbl1\u3
的两个递归子句是互斥的(在某些情况下),我们具体化了 术语相等,然后根据该值编制索引:

这就是发挥作用的原因:

dbl2([], []). dbl2([E|Es], Xs) :- dbl2_(Es, Xs, E). dbl2_([], [E,E,E], E). dbl2_([E|Es], Xs, E0) :- =(E0, E, T), t_dbl2_(T, Xs, E0, E, Es). t_dbl2_(true, [E|Xs], _, E, Es) :- dbl2_(Es, Xs, E). t_dbl2_(false, [E0,E0,E0|Xs], E0, E, Es) :- dbl2_(Es, Xs, E). dbl2([],[])。 dbl2([E|Es],Xs):- dbl2(Es,Xs,E)。 dbl2_([],[E,E,E],E)。 dbl2|([E|Es],Xs,E0):- (E0,E,T), t_dbl2_(t,Xs,E0,E,Es)。 t_dbl2_(真,[E | Xs],_,E,Es):- dbl2(Es,Xs,E)。 t_dbl2_(假[E0,E0,E0 | Xs],E0,E,Es):- dbl2(Es,Xs,E)。 使用SWI Prolog的示例查询:

?- dbl0([a],Xs). Xs = [a, a, a] ; false. ?- dbl1([a],Xs). Xs = [a, a, a]. ?- dbl2([a],Xs). Xs = [a, a, a]. ?- dbl0([a,b,b],Xs). Xs = [a, a, a, b, b, b, b] ; false. ?- dbl1([a,b,b],Xs). Xs = [a, a, a, b, b, b, b] ; false. ?- dbl2([a,b,b],Xs). Xs = [a, a, a, b, b, b, b]. ?-dbl0([a],Xs)。 Xs=[a,a,a]; 错。 ?-dbl1([a],Xs)。 Xs=[a,a,a]。 ?-dbl2([a],Xs)。 Xs=[a,a,a]。 ?-dbl0([a,b,b],Xs)。 Xs=[a,a,a,b,b,b,b]; 错。 ?-dbl1([a,b,b],Xs)。 Xs=[a,a,a,b,b,b,b]; 错。 ?-dbl2([a,b,b],Xs)。 Xs=[a,a,a,b,b,b,b]。
要使上述代码更紧凑,请使用控件构造。

我正准备将此版本与@repeat合并使用时,我看到@repeat已经建议了它。因此,这本质上是@repeat所概述的更紧凑的版本:

list_dbl([],[]).
list_dbl([X],[X,X,X]).
list_dbl([A,B|Xs],DBL) :-
   if_(A=B,DBL=[A,B|Ys],DBL=[A,A,A,B|Ys]),
   list_dbl([B|Xs],[B|Ys]).
   ?- list_dbl([a],DBL).
DBL = [a,a,a]
   ?- list_dbl([a,b,b],DBL).
DBL = [a,a,a,b,b,b,b]
它通过@repeat产生与dbl2/2相同的结果:

list_dbl([],[]).
list_dbl([X],[X,X,X]).
list_dbl([A,B|Xs],DBL) :-
   if_(A=B,DBL=[A,B|Ys],DBL=[A,A,A,B|Ys]),
   list_dbl([B|Xs],[B|Ys]).
   ?- list_dbl([a],DBL).
DBL = [a,a,a]
   ?- list_dbl([a,b,b],DBL).
DBL = [a,a,a,b,b,b,b]
OP的示例查询按预期工作:

   ?- list_dbl([a,b,a,a,a,c,c],DBL).
DBL = [a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]
此外,这里还有@lambda.xy.x提供的一些示例查询。它们产生的结果与@repeat的dbl/2和@lambda.xy.x的dbl/2相同:

   ?- dif(Xs,[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]), list_dbl([a,b,a,a,a,c,c],Xs).
no

   ?- list_dbl(X,[a,a,a,b,b]).
no

   ?- list_dbl(L,[a,a,a,b,b,b]).
L = [a,b] ? ;
no

   ?- list_dbl(L,DBL).
DBL = L = [] ? ;
DBL = [_A,_A,_A],
L = [_A] ? ;
DBL = [_A,_A,_A,_A],
L = [_A,_A] ? ;
DBL = [_A,_A,_A,_A,_A],
L = [_A,_A,_A] ? ;
...

   ?- list_dbl([a,X,a],DBL).
DBL = [a,a,a,a,a],
X = a ? ;
DBL = [a,a,a,X,X,X,a,a,a],
dif(X,a),
dif(a,X)

   ?- length(L,_), list_dbl(L,DBL).
DBL = L = [] ? ;
DBL = [_A,_A,_A],
L = [_A] ? ;
DBL = [_A,_A,_A,_A],
L = [_A,_A] ? ;
DBL = [_A,_A,_A,_B,_B,_B],
L = [_A,_B],
dif(_A,_B) ? ;
DBL = [_A,_A,_A,_A,_A],
L = [_A,_A,_A] ? 

嗯,这个列表应该是一个普通的序言列表,t