我正在阅读解决代数问题的程序的源代码。它的一部分是尝试从0到9的每个数字的过程。这是它的源代码:
digit(0, 0) :- !.
digit(X, X).
digit(D, N) :-
N2 is N - 1 ,
digit(D, N2) .
当我跑这个并问我得到:
?- digit(X, 9).
X = 9 ;
X = 8 ;
X = 7 ;
X = 6 ;
X = 5 ;
X = 4 ;
X = 3 ;
X = 2 ;
X = 1 ;
X = 0.
我似乎不太明白为什么程序 digit 会这样做。有人可以向我解释一下吗?
感谢您的回答!
答案 0 :(得分:3)
首先,一些术语。 digit
在Prolog中被称为“谓词”,而不是“过程”或“函数”。使这一点变得重要的是“谓词”并不完全与函数或过程有关。谓词是对逻辑关系的描述,并且调用谓词会尝试满足由该关系定义的逻辑目标,其中可能存在零个,一个或多个解决方案。为了满足目标,它可以实例化任何未实例化的变量或术语(尚未赋值的那些)。
要理解digit
的行为,您希望通过理解谓词的作用来“阅读”它。在此上下文中digit(X, N)
的含义是“X是0到N范围内的数字”。如果N
为0,那么我们期望该定义只有X
的一个答案(0)。如果N > 0
那么我们希望有多个答案会使digit(X, N)
成立。为此编写的规则(谓词)是:
digit(0, 0) :- !.
digit(X, X).
digit(X, N) :- N2 is N - 1, digit(X, N2).
此处的排序非常重要,因为Prolog将尝试按给定的顺序匹配这些规则,如下所述。
第一个宣布的事实是:
digit(0, 0) :- !.
这表示0是0到0之间的唯一数字。我只说 因为剪切会告诉Prolog在满足这个目标后不再寻找更多答案。因此digit(0, 0)
将成立,目标digit(X, 0).
将生成X = 0
并完成。
接下来是:
digit(X, X).
这表明X
是从0到X
的有效数字。没有削减,因此在满足该规则后可以寻求后续解决方案。 digit(X, 9)
之类的目标将与此规则匹配,并生成X = 9
。请注意,当您输入digit(X, 9)
时,第一个找到的结果是X = 9
,因为这是遇到的第一个符合digit(X, 9)
目标的规则。
最后,有:
digit(X, N) :- N2 is N - 1, digit(X, N2).
如果X
是从N
到X
的数字,则0
是从0到N - 1
的数字N2
是N-1
用于实例化值digit(X, 9)
)。因此,如果我输入目标digit(X, X)
,它首先会满足digit(X, X)
,如上所述。然后,由于该规则没有削减,当Prolog回溯更多解决方案时,它已经满足digit(X, 9)
因此将继续满足digit(X, 8)
并且在此过程中,尝试满足digit(X, N)
}如digit(X, 9)
规则所述。由于这是一个新目标(不是原始的digit(X, X)
目标),因此它从顶部开始,并且通过相同的逻辑,首先会遇到X = 8
并且满足X = 8
。因此,显示的第二个解决方案将是X = 9
(请记住第一个解决方案是digit(X, 7)
)。
此逻辑按顺序继续,满足digit(X, 6)
,X = 7
等,显示X = 6
,digit(X, 0)
等的解决方案,直到它最终到达{{1 }}。如上所述,digit(X, 0)
最终将满足digit(0, 0)
,产生解X = 0
,然后由于剪切而完成。此时,它已经耗尽了所有的解决方案和完成。
因此,结果为X = 9
,X = 8
,...,X = 0
。
关键在于Prolog继续(迭代/回溯)找到解决方案,找到所有可能的解决方案,直到找到所有可能性(由书面规则确定为谓词),或者直到这些可能性为止使用剪切截断。