求和到 Prolog 中的数字程序
Sum to a number program in Prolog
谁能解释一下这段代码是如何工作的。我是 Prolog 的新手,我无法像 Prolog 程序员那样思考。
当您输入一个数字后跟一个逗号和任何变量名时,它会为您提供该数字的总和
sum_to(1,1) :- !.
sum_to(N, R) :- N1 is N-1, sum_to(N1,TR), R is TR + N.
所以 sum_to(4, N) 给出 N = 10.
这是一个非常命令式的程序,实现了一个偶然用 Prolog 编写的归纳定义。
它涉及两个数字:
在第一个子句中,1 与 1 相关。!指示解释器应停止在 sum_to/2 谓词中寻找进一步的解决方案。
如果第一个子句不匹配(因为调用中的任何参数与 1 不同),则检查第二个子句。
现在我们只需:
将 N1 计算为 N-1
对 N1 进行递归调用,并在 TR 中获取一个值,使得 N1 和 TR 通过 sum_to/2
关联(即 TR 应该是直到 N1 的所有整数的总和) .一旦我们得到它,我们就将 R 计算为 TR 和 N 的总和。
对于第一个参数为 1 的 sum_to 关系是正确的。
如果 N-1 的 sum_to 关系正确,则 N 处的 sum_to 关系正确。
如果递归调用在每次调用中都“缩小”并最终达到最小值,计算将终止。它确实在每次调用时使 N 变小,最终会达到 1。(除非用 0 N 或更小的值调用此谓词。那么:灾难!)
看起来不错。
(顺便说一句,归纳定义倾向于从常数 x 到 +oo,即“向上”;上面我说的是从任何 N 向下移动到 1 的正确性。我这样做有道理吗?)
你的定义可以等效地写成
sum_to( N, R) :- N = 1, R = 1, !.
sum_to( N, R) :- N1 is N-1, sum_to( N1, R1), R is R1+N.
这是一个递归定义 -- 它包含对与谓词本身相同的谓词的调用。在您始终使用自由变量作为第二个参数并使用具体(希望是正数)数字作为第一个参数来调用它的情况下,它表示一个函数,该函数根据给定的第一个参数计算第二个参数的值。
因此你得到的是一个递归函数定义。
现在让我们来看一些例子,从最简单到越来越复杂:
sum_to( 1, R1) :- 1 = 1, R1 = 1, !.
\______________/
R1 = 1.
sum_to( 2, R2) :- N1 is 2-1, sum_to( N1, R1), R2 is R1+2.
\________/
N1 is 1, sum_to( 1, R1),
\____________/
R1 = 1, R2 is 1+2
\_____________________________________/
R2 = 3.
sum_to( 3, R3) :- N2 is 3-1, sum_to( N2, R2), R3 is R2+3.
\________/
N2 is 2, sum_to( 2, R2),
\____......____/
\__________________/
R2 = 3, R3 is 3+3
\_____________________________________________/
R3 = 6.
对吧?随着从左到右执行目标,我们的变量一个接一个地获得它们的具体值,从而实现下一个目标的执行,下一个 instantiate 更多变量,直到知道最终值。
现在sum_to( 4, R4)
.
谁能解释一下这段代码是如何工作的。我是 Prolog 的新手,我无法像 Prolog 程序员那样思考。 当您输入一个数字后跟一个逗号和任何变量名时,它会为您提供该数字的总和
sum_to(1,1) :- !.
sum_to(N, R) :- N1 is N-1, sum_to(N1,TR), R is TR + N.
所以 sum_to(4, N) 给出 N = 10.
这是一个非常命令式的程序,实现了一个偶然用 Prolog 编写的归纳定义。
它涉及两个数字:
在第一个子句中,1 与 1 相关。!指示解释器应停止在 sum_to/2 谓词中寻找进一步的解决方案。
如果第一个子句不匹配(因为调用中的任何参数与 1 不同),则检查第二个子句。
现在我们只需:
将 N1 计算为 N-1
对 N1 进行递归调用,并在 TR 中获取一个值,使得 N1 和 TR 通过
sum_to/2
关联(即 TR 应该是直到 N1 的所有整数的总和) .一旦我们得到它,我们就将 R 计算为 TR 和 N 的总和。对于第一个参数为 1 的 sum_to 关系是正确的。
如果 N-1 的 sum_to 关系正确,则 N 处的 sum_to 关系正确。
如果递归调用在每次调用中都“缩小”并最终达到最小值,计算将终止。它确实在每次调用时使 N 变小,最终会达到 1。(除非用 0 N 或更小的值调用此谓词。那么:灾难!)
看起来不错。
(顺便说一句,归纳定义倾向于从常数 x 到 +oo,即“向上”;上面我说的是从任何 N 向下移动到 1 的正确性。我这样做有道理吗?)
你的定义可以等效地写成
sum_to( N, R) :- N = 1, R = 1, !.
sum_to( N, R) :- N1 is N-1, sum_to( N1, R1), R is R1+N.
这是一个递归定义 -- 它包含对与谓词本身相同的谓词的调用。在您始终使用自由变量作为第二个参数并使用具体(希望是正数)数字作为第一个参数来调用它的情况下,它表示一个函数,该函数根据给定的第一个参数计算第二个参数的值。
因此你得到的是一个递归函数定义。
现在让我们来看一些例子,从最简单到越来越复杂:
sum_to( 1, R1) :- 1 = 1, R1 = 1, !.
\______________/
R1 = 1.
sum_to( 2, R2) :- N1 is 2-1, sum_to( N1, R1), R2 is R1+2.
\________/
N1 is 1, sum_to( 1, R1),
\____________/
R1 = 1, R2 is 1+2
\_____________________________________/
R2 = 3.
sum_to( 3, R3) :- N2 is 3-1, sum_to( N2, R2), R3 is R2+3.
\________/
N2 is 2, sum_to( 2, R2),
\____......____/
\__________________/
R2 = 3, R3 is 3+3
\_____________________________________________/
R3 = 6.
对吧?随着从左到右执行目标,我们的变量一个接一个地获得它们的具体值,从而实现下一个目标的执行,下一个 instantiate 更多变量,直到知道最终值。
现在sum_to( 4, R4)
.