消除列表元素的连续重复。
我的解决方案是:
compress([X,X|Xs], Q) :-
compress([X|Xs], Q).
compress([X,Y|Xs], Q) :-
X \= Y,
compress([Y|Xs], QR),
append([X], QR, Q).
compress([X|[]], Q) :-
compress([], QR),
append([X], QR, Q).
compress([], []).
而且,由于我是初学者,而且我没有逻辑范式的经验,我请你说出我可以改进的内容,以及为什么我的解决方案不尽如人意。
例如,X \= Y
看起来并不漂亮。
答案 0 :(得分:5)
我们从谓词的名称开始。
为什么使用命令式来表示关系?一个好的Prolog程序可用于所有方向,而命令式总是建议一个特定的方向或使用模式。因此,请选择声明性名称,并注明通用性和logical-purity。
接下来,最常见的查询是什么:
dif/2
不是很好!我们希望这会产生至少一些答案。
如果我们使用迭代深化怎么办:
?- length(Ls, _), compress(Ls, Cs). Ls = Cs, Cs = [] ; Ls = Cs, Cs = [_G841] ; Ls = [_G841, _G841], Cs = [_G841] ; Ls = [_G841, _G841, _G841], Cs = [_G841] .
嗯!缺少相当多的答案!元素不同的情况如何?正如您已经直观地预期的那样,使用不纯的谓词会导致这种影响。
因此,使用 prolog-dif ,即phrase/2
,表示两个词不同。它可以在各个方向使用!
此外,DCG( dcg )在描述列表时通常很有用。
所以,总的来说,这是怎么回事:
compression([]) --> []. compression([L|Ls]) --> [L], compression_(Ls, L). compression_([], _) --> []. compression_([X|Xs], L) --> ( { X = L }, compression_(Xs, L) ; { dif(X, L) }, [X], compression_(Xs, X) ).
我们使用接口谓词session_write_close();
来处理DCG。
用法示例:
?- phrase(compression(Ls), Cs). Ls = Cs, Cs = [] ; Ls = Cs, Cs = [_G815] ; Ls = [_G815, _G815], Cs = [_G815] . ?- length(Ls, _), phrase(compression(Ls), Cs). Ls = Cs, Cs = [] ; Ls = Cs, Cs = [_G865] ; Ls = [_G865, _G865], Cs = [_G865] ; Ls = Cs, Cs = [_G1111, _G1114], dif(_G1114, _G1111) .
从这里拿走它!改善决定论,找到更好的名字等。
答案 1 :(得分:4)
在 the answer by @mat (+ 1)的基础上,为什么不为这样的案例提高确定性:
?- phrase(compression([a,a,b,b,b,c,c,c,c,d]), Xs). Xs = [a, b, c, d] ; false.
使用 ; false
,SWI prolog-toplevel表示目标没有成功确定。
我们可以使用if_//3
- dcg类似if_/3
改善compression_//2
:
compression_([], _) --> []. compression_([X|Xs], L) --> if_(X = L, % is this item equal to previous one? compression_(Xs, L), % yes: old "run" goes on ([X], compression_(Xs, X))). % no: new "run" starts
示例查询:
?- phrase(compression([a,a,b,b,b,c,c,c,c,d]), Xs).
Xs = [a, b, c, d]. % succeeds deterministically