我对CLP在Prolog中的工作方式感到非常困惑。我不仅发现很难看到它的好处(我确实在特定的情况下看到了它,但发现很难概括这些好处),更重要的是,我很难想出如何正确地编写递归谓词。以下哪项是CLP(R)方式的正确形式?
factorial(0, 1).
factorial(N, F):- {
N > 0,
PrevN = N - 1,
factorial(PrevN, NewF),
F = N * NewF}.
或
factorial(0, 1).
factorial(N, F):- {
N > 0,
PrevN = N - 1,
F = N * NewF},
factorial(PrevN, NewF).
换句话说,我不确定什么时候应该在约束之外编写代码。对我来说,第一种情况似乎更符合逻辑,因为PrevN
和NewF
属于约束。但如果这是真的,我很好奇在递归函数中使用约束之外的谓词在哪些情况下有用。
你的帖子中有几个重叠的问题,可能太多了,无法在一篇帖子中连贯地解决,让你完全满意。
因此,我想首先陈述一些一般原则,然后—基于此;对你发布的代码做一些具体的评论。
首先,我想谈谈我认为在你的情况下最重要的一点:
LP&substeq;CLP
这意味着CLP可以被视为逻辑编程(LP)的超集。是否将其视为适当的超集,或者事实上,将它们视为表示同一概念更有意义,这在一定程度上是有争议的。在我个人看来,没有约束的逻辑编程比有限制的更难理解,可用性也更低。考虑到即使是最早的Prolog系统也有像dif/2
这样的约束,以及像;(=)/2
完全符合"约束"的概念,如果边界存在的话,对我来说至少有点人为,这表明:
LP&近似值;CLP
尽管如此,与CLP(任何类型)合作时的关键概念是约束可用作谓词,并像所有其他谓词一样在Prolog程序中使用。
因此,无论您的目标是factorial(N, F)
还是{ N > 0 }
,至少在原则上都是相同的概念:两者都意味着保持。
请注意语法:CLP(ℛ)约束的形式为{ C }
,即;前缀表示法中的{}(C)
。
请注意,目标factorial(N, F)
是而不是CLP(ℛ)约束!以下两者都不是:
?-{阶乘(N,F)}。错误:未处理的异常:type_ERROR({factorial(_3958,_3960)},…)
因此,{ factorial(N, F) }
也是而不是CLP(ℛ)约束!
因此,您的第一个示例已经无法单独使用了。(此外,子句头中有一个语法错误:factorial (
,因此它也根本无法编译。)
学习使用约束求解器时,请查看它提供的谓词。例如,CLP(ℛ)提供了{}/1
和其他一些谓词,并有一个专用的语法用于声明关系;持有大约浮点数(在这种情况下)。
其他约束求解器提供其自己的谓词,用于描述其<em]各自>域的实体。例如,CLP(FD)提供了(#=)/2
和其他一些谓词来推理整数。dif/2
允许您推理任何Prolog术语。等等。
从程序员的角度来看,这与使用Prolog系统的任何其他谓词完全相同,无论它是内置的还是源于库。原则上,一切都是一样的:
像list_length(Ls, L)
这样的目标可以理解为:"列表的长度Ls
是L
。">
像{ X = A + B }
这样的目标可以读作:数字X
等于A
和;B
。例如,如果您正在使用CLP(Q),很明显,我们在这里谈论的是有理数;案例
在第二个示例中,子句的正文是形式为(A, B)
的连词,其中A
是CLP(&Rscr;)约束,B
是形式factorial(PrevN, NewF)
的目标。
重点是:CLP(&Rscr;)约束是也是目标!看看:
?-write_canonic({a,b,c})。{','(a,',',(b,c))}是的
因此,您只需使用library(clpr)
中的{}/1
,这是它导出的谓词之一。
您认为PrevN
和NewF
属于约束是正确的。但是,factorial(PrevN, NewF)
不是CLP(&Rscr;)实现的用于对浮点数进行推理的迷你语言的一部分。因此,不能将此目标引入CLP(&Rscr;)特定部分。
从程序员的角度来看,CLP的一个主要吸引力在于它完全无缝地融入中,以至于事实上几乎无法将其与;it:约束只是谓词,并且像所有其他约束一样写下来;目标。
是否将库谓词标记为"约束"几乎没有任何区别:所有谓词都可以被视为;约束,因为它们只能约束答案,所以永远不要放松它们。
请注意,您发布的两个示例都是递归的!这太完美了;好的。事实上,递归谓词可能是大多数使用的情况;未来的制约因素。
但是,对于阶乘的具体情况,Prolog系统的CLP(FD)约束可能是更好的;适合,因为他们完全致力于推理整数。