当我们使用带有cut运算符的append时会出现什么问题?
append2([],L,L):-!.
append2([H|T],L,[H|TL]):-append2(T,L,TL).
我尝试了几种不同的输入,但它总是成功的。
?- append2([1,2],[5],L).
L = [1, 2, 5].
?- append2([1,2],[1,2],L).
L = [1, 2, 1, 2].
?- append2([],[1,2],L).
L = [1, 2].
?- append2([1,2],[],L).
L = [1, 2].
答案 0 :(得分:8)
有时真的有必要引入绿色切割 - 甚至是append/3
,但必须注意这样的切割仍然是绿色切割。也就是说,这种切割可以提高效率(在某个水平上)并且不会影响答案。
引入绿色切割有一个非常简单的经验法则:如果你在没有任何防护的情况下将切割添加到纯粹的单调程序中,你可以非常肯定它将是一个破坏其意义的红色切口你的计划。
这个经验法则很少有例外。例如,如果没有进一步的规则等,你可以在一个可变的自由目标之后添加一个切口。试图找出受切割影响的案例绝对是一个很好的训练。
但回到您的计划append2/3
。目前,即使替代规则确实适用,剪辑总是会削减,在这种情况下剪辑会删除我们想要避免的答案。
那么第一个条款何时才是唯一的相关条款?
如果第一个参数是[]
,那么append2([], Xs, Ys).
- 但是如果最后一个参数是[]
(还有更多的情况更复杂)。让我们尝试使用原始无切割定义的两种情况:
?- append([], Ys, Zs). Ys = Zs. ?- append(Xs, Ys, []). Xs = Ys, Ys = [] ; false.
因此,在第一种情况下,系统能够立即确定存在单个解决方案,同时产生答案。然而,在第二种情况下,Prolog系统不确定是否需要另一个答案 - 它可以说“让选择点保持开放”。这是一个遗憾,因为确定在这种情况下,只有一个答案存在是相当微不足道的。切割本来是理想的帮助。但无人看守的伤害会带来更大的伤害。
如果第三个参数是[]
:
append3(Xs, Ys, Zs) :-
( Zs == [] -> ! ; true ),
Xs = [],
Ys = Zs.
append3([X|Xs], Ys, [X|Zs]) :-
append3(Xs, Ys, Zs).
如果只知道第3个参数,那么这个程序现在更有效率,因为它不会让选择点保持打开状态。
?- append(Xs,Ys,[1]). Xs = [], Ys = [1] ; Xs = [1], Ys = [] ; false. ?- append3(Xs,Ys,[1]). Xs = [], Ys = [1] ; Xs = [1], Ys = [].
程序不一定更快,因为测试本身可能很昂贵。理想情况下,Prolog系统可以在内部执行此类操作,但有时程序员必须提供帮助。
答案 1 :(得分:6)
cuts有两种;绿色削减和红色削减。插入绿色剪切只是为了提高效率,而不是改变程序的语义。另一方面,红色削减。根据定义,绿色削减不会造成任何问题。
那么,如果切割不存在,行为会有什么变化吗?
让我们看看;对于要匹配的第一个子句,L1应与[],L2与L和L3与L一致,或者换句话说,L2与L3一致。
当L1为[]时,第二个子句不匹配;所以切割没有任何影响
当L1未实例化时: 如果此时已知L2和L3的长度,那么它们必须相等,否则第一个子句将不匹配;因此,第二个句子不能匹配,因为在每个步骤L3的长度减少1并且唯一的终止方法需要L2 = L3
如果L3或L2的长度未知: 那么我们就有问题,因为第二个条款可能会产生解决方案。
事实上:
3 ?- append2(L1,L2,[1,2,3]).
L1 = [],
L2 = [1, 2, 3].
4 ?- append2(L1,[1,2,3],L3).
L1 = [],
L3 = [1, 2, 3].
5 ?- append2(L1,L2,L3).
L1 = [],
L2 = L3.
6 ?- append2(L1,[E1,E2],L3).
L1 = [],
L2 = [E1, E2].
7 ?- append2(L1,L2,[E1,E2]).
L1 = [],
L2 = [E1, E2].
虽然我们期待:
8 ?- append(L1,L2,[1,2,3]).
L1 = [],
L2 = [1, 2, 3] ;
L1 = [1],
L2 = [2, 3] ;
L1 = [1, 2],
L2 = [3] ;
L1 = [1, 2, 3],
L2 = [] ;
false.
9 ?- append(L1,[1,2,3],L3).
L1 = [],
L3 = [1, 2, 3] ;
L1 = [_G24],
L3 = [_G24, 1, 2, 3] ;
L1 = [_G24, _G30],
L3 = [_G24, _G30, 1, 2, 3] ;
L1 = [_G24, _G30, _G36],
L3 = [_G24, _G30, _G36, 1, 2, 3] ;
L1 = [_G24, _G30, _G36, _G42],
L3 = [_G24, _G30, _G36, _G42, 1, 2, 3] ;
...
10 ?- append(L1,L2,L3).
L1 = [],
L2 = L3 ;
L1 = [_G22],
L3 = [_G22|L2] ;
L1 = [_G22, _G28],
L3 = [_G22, _G28|L2] ;
....
11 ?- append(L1,[E1,E2],L3).
L1 = [],
L3 = [E1, E2] ;
L1 = [_G78],
L3 = [_G78, E1, E2] ;
L1 = [_G78, _G84],
L3 = [_G78, _G84, E1, E2] ;
L1 = [_G78, _G84, _G90],
L3 = [_G78, _G84, _G90, E1, E2] ;
...
12 ?- append(L1,L2,[E1,E2]).
L1 = [],
L2 = [E1, E2] ;
L1 = [E1],
L2 = [E2] ;
L1 = [E1, E2],
L2 = [] ;
false.
答案 2 :(得分:5)
尝试最常见的查询示例:
?- append2(X, Y, Z).
答案 3 :(得分:3)
当前两个参数是可变的时,它将不起作用:
?- append(X, Y, [1, 2, 3]).
X = [],
Y = [1, 2, 3] ;
X = [1],
Y = [2, 3] ;
X = [1, 2],
Y = [3] ;
X = [1, 2, 3],
Y = [] ;
false.
?- append2(X, Y, [1, 2, 3]).
X = [],
Y = [1, 2, 3].