我收到了一个问题:
定义仅在其第二个参数时成立的2位谓词“增量” 是一个比第一个参数大的整数。例如,增量(4,5)应该成立,而增量(4,6)不应该持有。
所以我写道:
increment(0, 1) :-
!.
increment(A, B) :-
A is A - 1,
B is B - 1,
increment(A, B).
但是这似乎不像我想的那样有效。有人可以向我解释发生了什么,为什么这不能正常工作,甚至可以向我指出正确的方向?
答案 0 :(得分:3)
如何尝试:
increment(X,Y) :- Y is X+1.
我认为问题代码中的一个问题是A is A - 1
和B is B - 1
总是会失败。
A is A - 1
将失败,因为与A
统一的任何数字都不能等于A
减1。可能是您希望A is A - 1
重新分配{{1 }}到A
减1(这与其他多种编程语言的工作方式保持一致),但Prolog的工作方式则不同。一旦变量被统一为一个术语,则它将与该术语保持一致,直到Prolog回溯以寻找替代解决方案。
另一种更接近该问题建议的方法是引入两个新变量,这些变量可用于与减法结果统一,然后在递归调用中使用这两个变量:
A
(我建议改为使用increment(0, 1) :- !.
increment(A, B) :- X is A - 1, Y is B - 1, increment(X, Y).
。)
答案 1 :(得分:1)
这是一个不使用is/2
(即RHS的强制算术运算)的计算机。
:- use_module(library(clpfd)).
increment(X,Y) :-
assertion((var(X);integer(X))), % nice to check: X is unbound or integer
assertion((var(Y);integer(Y))), % nice to check: X is unbound or integer
assertion((nonvar(X);nonvar(Y))), % nice to check: at least one must be bound
Y #= (X+1). % the poodle's kernel
这基本上是succ/2
的扩展版本,不仅允许在ℕ中使用整数-最重要的是,它可以“双向”工作:X
或Y
可以是未绑定/通话时新鲜。
它使用来自#=
的约束“操作符library(clpfd)
,这比is/2
或=:=
都方便得多,这两个约束都要求应该使用什么运算符的左侧和右侧。
我免费投了一些assertion/1
。这些通常可以节省您的培根和/或作为“实时文档”。我听说从传统上讲,人们会使用对must_be/2
的调用,但是我发现它很脆弱且类似于C。将整个目标传递给assertion/1
恰恰是高级编程的样子!
用plunit
测试它:
:- begin_tests(increment).
test("X is unbound",true(X==21)) :-
increment(X,22).
test("Y is unbound",true(Y==22)) :-
increment(21,Y).
test("X and Y are bound and Y = X+1",true) :-
increment(21,22).
test("X and Y are bound and Y # X+1",fail) :-
increment(10,100).
:- end_tests(increment).
等等:
?- run_tests.
% PL-Unit: increment .... done
% All 4 tests passed
true.