2

我只是“学习”了 Prolog,但我并不真正了解函数中的输入和输出是什么。

例如

concatenate([X|L1], L2, [X|L3]) = concatenate (L1,L2,L3).
concatenate([],L,L).

这是什么意思?

If I write 
?- concatenate(X,[2,Y],[1,1,1,2,3]) 

它返回

X=[1,1,1],
Y=3.

所以这意味着第 3 个参数是第 1 和 2d 的连接,但是我们如何通过阅读函数的声明来知道这一点?谢谢

4

3 回答 3

5

只是补充两个已经很好的答案......

在 Prolog 中,您不会将事物视为具有参数输入和输出的“函数”(尽管它们确实如此),而是将其视为定义规则并尝试实例化任何变量参数(未实例化的变量)的“谓词”这样的方式,使规则是真实的。这个过程可能会导致没有解决方案、一个解决方案或多个解决方案,而您将获得所有解决方案。并非所有谓词都为未实例化变量的每个组合提供这种“完整功能”,或者如果有太多变量未实例化,则提供解决方案在逻辑上变得不切实际。在任何这些情况下决定参数的行为,以及谓词是否有任何解决方案,是谓词的逻辑,而不是输入或输出的任何正式声明。

让我们以给定concatenate的为例(注意我使用的是 GNU Prolog)。谓词的concatenate(L1, L2, L3)意思是“L1 与 L2 连接(按该顺序)给出 L3”,这比说“给定 L1 和 L2,在 L3 中提供它们的连接”更笼统,这意味着特定的输入和输出。

所以如果我输入:

concatenate( [1,2], [3,4], L3 ).

我得到:

L3 = [1,2,3,4]

(1 ms) yes
| ?-

这意味着 prolog 找到了一种解决谓词的方法,其中显示了L3. 我也可以输入这个:

concatenate( L1, [3,4], [1,2,3,4] ).

我会得到:

L1 = [1,2]

(1 ms) yes
| ?-

这意味着 prolog 找到了一种解决谓词的方法,其中显示了L1. 同样,如果我进入concatenate( [1,2], L2, [1,2,3,4] ),我会得到一个解决方案:L2 = [3,4].

让我们尝试一些更有趣的事情:

concatenate( L1, L2, [1,2,3,4] ).

Prolog 会为此找到解决方案,但我提供了两个未实例化的变量。因此,解决方案将涉及以下可能性:

L1 = [1,2,3,4]
L2 = [] ? ;

L1 = [1,2,3]
L2 = [4] ? ;

L1 = [1,2]
L2 = [3,4] ? ;

L1 = [1]
L2 = [2,3,4] ? ;

L1 = []
L1 = [1,2,3,4] ? ;

(1 ms) yes
| ?-

现在让我们试试这个:

concatenate( [1,2], L2, L3 ).

我得到:

L3 = [1,2|L2]

| ?-

L2在这种情况下,并且因此的可能性L3是无限的,因此 prolog 显示了一个通用解决方案。

在您的示例中,concatenate( X, [2,Y], [1,1,1,2,3] )同样的想法也适用。Prolog 将尝试找到满足“与 [2,Y] 连接的 X 给出 [1,1,1,2,3]”条件的 和 的实例化,并且 [2,Y] 是具有第一个元素X和第二个元素的列表元素。在这种情况下,只有您展示的一种解决方案。Y2Y

作为这个主题的变体,使用@DrH 描述的列表概念,如果你这样做了:

concatenate( X, [2|Y], [1,1,1,2,3] ).

你会得到X = [1,1,1]Y = [3]。请注意,如果您这样做:

concatenate( X, [2,Y], [1,1,1,2,3,4] ).

你得到'no'(没有解决方案),因为Y这里显示为一个原子,而不是一个列表(因为逗号语法)。换句话说,没有两个元素列表看起来像[2,Y]which,当与任何可能性连接时,X将 yield [1,1,1,2,3,4]。但如果你这样做:

concatenate( X, [2|Y], [1,1,1,2,3,4] ).

你会得到X = [1,1,1]Y = [3,4]因为现在我将未实例化的内容显示Y为列表的尾部,它本身就是一个列表,而不仅仅是一个原子(使用|语法)。

正如@WillNess 指出的那样,如果您未实例化某些变量,给定谓词的文档将告诉您希望该谓词的行为。一个写得很好的序言谓词比一个写得不好或限制性更强的谓词更有可能“做你期望或想要的”。这不会使更受限制的谓词“坏”,因为它可能会起到非常有用的作用。它不会那么有用。在编写自己的序言谓词时,您会考虑这些事情。

Prolog 就像围棋游戏:一些简单的规则,但有许多有趣的可能性。

于 2013-07-23T13:33:05.223 回答
3

应该有一个注释,其中包含谓词的每个参数的描述对它们的期望:预设(因此可用作输入)、自由(尚未设置,因此用于输出)或无偏好(因此两者都可以)。

查看SWI Prolog-4.1 Notation of Predicate Descriptions 的文档。他们使用

  • +对于完全实例化的参数
  • -参数必须是未绑定的,将用于输出
  • ?正确类型的部分实例化参数(请注意,未实例化的变量是任何类型的部分术语)。

以及其他一些更高级的选项。

有时源代码就像您的示例一样简单,可以认为哪个是哪个是不言而喻的。

于 2013-07-23T11:47:08.063 回答
1
concatenate([X|L1], L2, [X|L3]) :-
    concatenate(L1, L2, L3).

首先,Prolog 中的列表由头部(此处X)和尾部(其余列表,此处L1L3)组成。所以这个谓词说有一个列表,它的第一个元素是X,如果你将它与 连接L2,你会得到一个列表,它的第一个元素也是X,而它的尾巴是 some L3。为了使这个谓词为真,谓词concatenate(L1, L2, L3)不失败也是必要的,也就是说,第一个列表的其余部分可以与第二个列表连接,它们将产生第三个。

由于参数可以是输入变量或输出变量,您可以使用未知变量调用此谓词,或者如果您有三个列表,您可以通过连接其他两个来检查其中一个是否可以创建。

第二个谓词concatenate([], L, L)表示如果第一个列表为空,则连接的结果是第二个列表。

让我们L1成为。[1, 2, 3]_ 让我们调用我们的谓词,看看里面发生了什么:L2[4, 5, 6]

concatenate(L1, L2, L3).
concatenate([1, 2, 3], [4, 5, 6], L3).    // First predicate can be matched
concatenate([1 | [2, 3]], [4, 5, 6], [1 | A1]).    // Now [2, 3] is L1 and A1 is the current L3

concatenate([2, 3], [4, 5, 6], A1).    // First predicate can be matched
concatenate([2 | [3]], [4, 5, 6], [2 | A2]).    // Now [3] is L1 and A2 is L3

concatenate([3], [4, 5, 6], A2).    // First predicate can be matched
concatenate([3 | []], [4, 5, 6], [3 | A3]).    // Now [] is L1 and A3 is L3

concatenate([], [4, 5, 6], A3).    // Second predicate can be matched
concatename([], [4, 5, 6], [4, 5, 6]).

我们有一个退出条件,一个没有主体的谓词。现在我们倒退(这称为回溯,在我们的搜索空间中倒退)。让我们用结果替换 A* 变量:

concatenate([], [4, 5, 6], [4, 5, 6]).

concatenate([3 | []], [4, 5, 6], [3 | [4, 5, 6]]).

concatenate([3], [4, 5, 6], [3, 4, 5, 6]).

concatenate([2 | [3]], [4, 5, 6], [2 | [3, 4, 5, 6]]).

concatenate([2, 3], [4, 5, 6], [2, 3, 4, 5, 6]).

concatenate([1 | [2, 3]], [4, 5, 6], [1 | [2, 3, 4, 5, 6]]).

concatenate([1, 2, 3], [4, 5, 6], [1, 2, 3, 4, 5, 6]).
于 2013-07-23T11:26:25.413 回答