您发布的代码(几乎)正确。只需要交换从句的顺序(为了使这个谓词定义在生成方式下具有生产力)即可。
append( [], X, X). %
append( [X | Y], Z, [X | W]) :- append( Y, Z, W). %
这定义了三个参数之间的关系,假设为
A
、
B
和
C
。
你的第一行表示:“如果
A
和
C
都是非空列表,并且它们具有相同的
头(即第一个元素),则
C
是将
A
和
B
连接起来的结果,
C
的
尾巴是将
A
的尾部与第二个参数
B
连接的结果。”
a a
----------
b b
c c
. d d
e e
. .
或者从左到右:
a | b c .
| d e .
a | b c d e .
append( [],
Z,
Z ).
append( [X | Y ],
Z,
[X | W ] ) :- append(
Y, Z, W).
考虑一下,这是完全有道理的。我们想要定义
append/3
关系,我们知道它应该是什么,所以我们只需要写下一些我们希望它实现的显而易见的事实,也就是它必须遵循的规则。
假设我们已经为此定义了代码,那么它必须遵循哪些规则呢?显然,将一个列表的尾部与另一个列表连接起来会给我们一个结果列表的尾部,这个结果列表是将原列表与第二个列表连接后得到的。
这定义了我们如何“滑动”第一个列表。但是如果没有更多地方可以滑动怎么办?如果我们已经到达了该列表的末尾怎么办?那么我们就到达了空列表,并且将空列表与另一个列表连接起来会将该列表作为结果返回。这是显而易见的。这就是你的代码中第二行告诉我们的内容,它说,“将一个
空列表与另一个列表连接起来会产生该列表作为结果”。
令人惊讶的是,写下
append/3
必须遵循的这两个规则,与写下定义本身是相同的。
补充:这是从声明性的角度来解释的;请查看m09提供的答案,它更多地从操作的角度来展示。
append
的编码方式编写它吗?你已经发现了它的实现方式(它是你问题中的前两行代码)。 - aioobe