为什么在SWI Prolog中,我用`|符号得到结果?

时间:2017-06-01 20:06:15

标签: list prolog

我有以下代码将等效对象的序列组合在一起:

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]]

您是否注意到每个列表中最后一个元素之前的|符号?我不知道为什么会出现以及如何解决它。有什么想法吗?

1 个答案:

答案 0 :(得分:3)

列表是一种具有两种仿函数/常量的数据类型:

  • 没有参数的空列表[];和
  • " cons" [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]] .