我只是“学会”了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个的连接,但是我们怎么能通过阅读函数的声明来知道呢? 感谢
答案 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]
| ?-
在这种情况下,L2
和L3
的可能性是无限的,因此prolog正在显示一般解决方案。
在您的示例中,concatenate( X, [2,Y], [1,1,1,2,3] )
适用相同的想法。 Prolog将尝试查找X
和Y
的实例,这些实例满足“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
)和一个尾部(其余列表,此处为L1
和L3
)。所以这个谓词说有一个列表,它的第一个元素是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]).