尝试学习序言

时间:2020-09-09 15:26:42

标签: prolog

我收到了一个问题:

定义仅在其第二个参数时成立的2位谓词“增量” 是一个比第一个参数大的整数。例如,增量(4,5)应该成立,而增量(4,6)不应该持有。

所以我写道:

increment(0, 1) :-
    !.
increment(A, B) :-
    A is A - 1,
    B is B - 1,
    increment(A, B).

但是这似乎不像我想的那样有效。有人可以向我解释发生了什么,为什么这不能正常工作,甚至可以向我指出正确的方向?

2 个答案:

答案 0 :(得分:3)

如何尝试:

increment(X,Y) :- Y is X+1.

我认为问题代码中的一个问题是A is A - 1B 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的扩展版本,不仅允许在ℕ中使用整数-最重要的是,它可以“双向”工作:XY可以是未绑定/通话时新鲜。

它使用来自#=的约束“操作符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.