我有以下代码将等效对象的序列组合在一起:
pack([], []).
pack([X], [X]).
pack([H, T|TS], [H|TR]):-
H \= T,
pack([T|TS], TR).
pack([H, H|HS], [[H|TFR]|TR]):-
pack([H|HS], [TFR|TR]).
我的意见是:
pack([1,1,1,1,2,3,3,1,1,4,5,5,5,5], X).
结果我得到了:
[[1,1,1|1],2,[3|3],[1|1],4,[5,5,5|5]]
您是否注意到每个列表中最后一个元素之前的|
符号?我不知道为什么会出现以及如何解决它。有什么想法吗?
答案 0 :(得分:3)
列表是一种具有两种仿函数/常量的数据类型:
[]
;和[element|list]
。如第二个选项所示,缺点的第二个参数应为列表。这可以是另一个缺点(并因此递归地进一步),或者是空列表。尽管如此,Prolog并没有真正输入,所以你可以使用整数,字符......作为第二项,但它不列表。
现在的问题是," 我们如何构建这样奇怪的列表"。在这个答案中,我使用了一个较小的例子来重现错误,因为它使事情变得更容易:
?- trace.
true.
[trace] ?- pack([1,1], X).
Call: (7) pack([1, 1], _G1066) ? creep
Call: (8) 1\=1 ? creep
Fail: (8) 1\=1 ? creep
Redo: (7) pack([1, 1], _G1066) ? creep
Call: (8) pack([1], [_G1144|_G1141]) ? creep
Exit: (8) pack([1], [1]) ? creep
Exit: (7) pack([1, 1], [[1|1]]) ? creep
X = [[1|1]] .
如果我们打包两个元素,就会出现问题。首先我们致电pack([1,1],X)
。
首先触发第三个子句,但H \= T
项失败。因此,结果Prolog 重做调用,但现在使用最后一个子句。在最后一句中,我们看到了一些奇怪的东西:
pack([H, H|HS], [[H|TFR]|TR]):-
pack([H|HS], [TFR|TR]).
我们看到的是,我们使用pack/2
对[TFR|TR]
执行递归调用。这意味着[TFR|TR]
应该是列表列表。但第二个子句不生成列表列表,而只生成项目列表。所以错误在:
pack([X], [X]).
%% ^ list of items??
因此我们需要做的就是解决错误,将第二个子句重写为:
pack([X], [[X]]).
%% ^ list of list
现在我们已经解决了这个问题,但我们还没有解决:第三个句子中还存在类型错误:
pack([H, T|TS], [H|TR]):-
%% ^ item instead of a list?
H \= T,
pack([T|TS], TR).
我们可以简单地将其列为项目列表:
pack([H, T|TS], [[H]|TR]):-
%% ^ list
H \= T,
pack([T|TS], TR).
现在我们获得以下代码:
pack([], []).
pack([X], [[X]]).
pack([H, T|TS], [[H]|TR]):-
H \= T,
pack([T|TS], TR).
pack([H, H|HS], [[H|TFR]|TR]):-
pack([H|HS], [TFR|TR]).
然后我们获得:
?- pack([1,1,1,1,2,3,3,1,1,4,5,5,5,5], X).
X = [[1, 1, 1, 1], [2], [3, 3], [1, 1], [4], [5, 5, 5|...]] [write]
X = [[1, 1, 1, 1], [2], [3, 3], [1, 1], [4], [5, 5, 5, 5]] .
修改强>:
如果只有一个元素,您显然不想构建列表。这使得问题变得更加困难。有两种选择:
最后一个是非常微不足道的,所以让我们做第一个。在这种情况下,第二个条款确实应该是:
pack([X],[X]).
现在第二个条款应为:
pack([H, T|TS], [H|TR]):-
H \= T,
pack([T|TS], TR).
也是。但最后一个条款更难:
pack([H, H|HS], [[H|TFR]|TR]):-
pack([H|HS], [TFR|TR]).
这里有两种可能性:
TFR
是一个项目列表,在这种情况下,我们只是前面的列表;或TFR
不是列表,在这种情况下我们构建一个列表。为了解决这个问题,我们可以定义一个谓词:
prepend_list(H,[HH|T],[H,HH|T]).
prepend_list(H,X,[H,X]) :-
X \= [_|_].
然后使用:
pack([H, H|HS], [HTFR|TR]):-
pack([H|HS], [TFR|TR]),
prepend_list(H,TFR,HTFR).
现在我们获得:
pack([], []).
pack([X], [X]).
pack([H, T|TS], [H|TR]):-
H \= T,
pack([T|TS], TR).
pack([H, H|HS], [HTFR|TR]):-
pack([H|HS], [TFR|TR]),
prepend_list(H,TFR,HTFR).
prepend_list(H,[HH|T],[H,HH|T]).
prepend_list(H,X,[H,X]) :-
X \= [_|_].
但请注意,如果您想pack/2
列出自己,此程序将失败。在这种情况下,最好还是使用后处理步骤。
现在构建:
?- pack([1,1,1,1,2,3,3,1,1,4,5,5,5,5], X).
X = [[1, 1, 1, 1], 2, [3, 3], [1, 1], 4, [5, 5, 5|...]] [write]
X = [[1, 1, 1, 1], 2, [3, 3], [1, 1], 4, [5, 5, 5, 5]] .