在prolog中输出或输入

时间:2013-07-23 09:38:54

标签: prolog

我只是“学会”了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个和第2个的连接,但是我们怎么能通过阅读函数的声明来知道呢? 感谢

3 个答案:

答案 0 :(得分: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]

| ?-

在这种情况下,L2L3的可能性是无限的,因此prolog正在显示一般解决方案。

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

作为此主题的变体,使用@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] ).

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

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

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

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

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

答案 1 :(得分:2)

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

查看documentation for SWI Prolog - 4.1 Notation of Predicate Descriptions。他们使用

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

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

有时候源代码就像你的例子一样简单,可以认为它是不言而喻的。

答案 2 :(得分:1)

concatenate([X|L1], L2, [X|L3]) :-
    concatenate(L1, L2, L3).

首先,Prolog中的列表包括一个头部(此处为X)和一个尾部(其余列表,此处为L1L3)。所以这个谓词说有一个列表,它的第一个元素是X,如果你用L2连接它,你将获得一个列表,其第一个元素也是X,而它的尾部是一些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]).