何时可在Prolog中安全省略临时计算的变量存储?
问题背景
我编写了一个计算阶乘的简单Prolog程序,运行正常:
factorial(1,1). factorial(Number, Factorial):- Number>1,Number1 is Number-1, factorial(Number1, Factorial1), Factorial is Factorial1*Number.
但如果不创建临时变量Number1,直接用Number-1作为factorial的参数调用,程序始终返回false:
factorial(1,1). factorial(Number, Factorial):- Number>1, factorial(Number-1, Factorial1), Factorial is Factorial1*Number. ?- factorial(5,N). false.
基于正确的阶乘程序,我又写了计算二项式系数的程序,这里直接将N-K的计算结果作为factorial的参数传入,无需临时变量也能正常运行:
binomial(N,K,R):-factorial(N,FN),factorial(K,FK),factorial(N-K,FNK),R is FN//(FK*FNK). ?- binomial(8,5,N). N = 56 ; false.
我想询问:何时可确保Prolog将计算结果作为其他谓词输入时,无需临时变量也能正常运行?
解答
核心区别在于谓词参数是否会被Prolog的算术求值机制自动处理:
你的
factorial谓词第一个参数需要的是具体数值,而非未求值的算术表达式。在错误的阶乘代码里,factorial(Number-1, Factorial1)传递的是Number-1这个表达式结构本身,不是计算后的数值;而你的factorial子句只有匹配1或大于1的数值的规则,无法匹配这种表达式结构,因此运行失败。二项式系数代码中
factorial(N-K, FNK)能正常运行,是因为调用binomial(8,5,N)时,N和K都已绑定为具体数值(8和5),此时N-K会被Prolog自动求值为3,再传递给factorial。换句话说,当表达式中的所有变量都已绑定为具体数值时,Prolog会在调用谓词前自动计算表达式结果,将数值作为参数传入。
总结可直接用表达式作为参数的场景:
- 表达式内所有变量都已绑定为具体数值(整数、浮点数等),此时Prolog会自动求值表达式,将结果数值传入谓词。
- 如果表达式存在未绑定的变量,Prolog不会自动求值,会把表达式结构直接传递给谓词;若你的谓词没有处理这种结构的规则,就会运行失败,必须先用
is将表达式求值后存入临时变量,再传递变量。
比如阶乘递归场景中,Number虽为绑定数值,但Number-1在谓词调用的参数位置时,Prolog不会自动求值(仅is右侧会触发算术求值),因此必须用Number1 is Number-1先计算出数值,再将Number1传给factorial。
内容的提问来源于stack exchange,提问作者Cardstdani

