坚持序言程序

Stuck with prolog program

所以我遇到了我的 Prolog 问题。假设您有这样的要求:

?-num(100,200). 

程序应该 return 这个间隔中所有可以从还原神智学中生成数字 6 的数字 (123=1+2+3=6 所以我应该 return 123, 105 = 1+0+5=6 所以我也应该 return 它。我已经有了可以为此计算的程序。我有一些东西,我很确定我应该工作,但它甚至 运行。这就是我到目前为止所得到的还原效果完美

num(X,Y):-
    repeat,
    reduct(X,T),
    T=:=6 ->write(X),
    X is X+1,
    (X=:=Y),!.

没有什么可以添加到有价值的潜伏者评论中...

他建议的地方

You appear to be trying to use it as an assignment statement, which won't work. Prolog doesn't do assignments. It does unifications.

你应该推断出一些关于 loops 的含义。您的代码 无法 工作,因为它缺少 'generate-and-test' 的 'generate' 部分,您在故障驱动循环中编写了该部分。

因此,要么添加生成器,例如 between/3,要么使用递归,而不是故障驱动循环。

这是一个 1 班轮,可能会帮助您完成作业。

?- [user].
|: num(X,Y) :- between(X,Y,N), number_codes(N,Cs), aggregate(sum(D),C^(member(C,Cs),D is C-0'0),6), writeln(N).

?- num(100,200).
105
true ;
114
true ;
123
true ;
132
true ;
141
true ;
150
true ;
false.

除了 CapelliC 的建议使用 between/3(在这种情况下,这是迭代整数范围的理想选择),让我们分解您现有的谓词以查看问题所在。

注意运算符优先级

',' 高于 ->。所以你的谓词表现得像这样:

num(X,Y):-
    repeat,
    reduct(X,T),
    T=:=6 ->
    (  write(X),
       X is X+1,
       (X=:=Y), !
    ).

一旦 T =:= 6 失败,就会进入无限循环,repeat, reduct(X, T), T =:= 6 因为 X 永远不会改变,因此 T 永远不会改变,所以T =:= 6 继续失败,Prolog 回溯repeat。那么,在您的代码中,这是一个无限循环。

您使用 repeat 和 cut (!) 的策略在这里不起作用

形式上,你所拥有的是:

repeat,
<do some queries>,
X =:= Y,    % succeed if X and Y have the same value
!

repeat 总是成功。任何时候 Prolog 一直回溯到 repeat,然后它会再次向前移动寻找更多的解决方案。剪切告诉 Prolog 在该点(剪切点)之前不要回溯。这里的问题是 X,它在 num(100, 200) 查询调用开始时已经实例化(到 100),永远不能与设置为 200 的 Y 具有相同的值(见下文)。所以 X =:= Y 总是会失败。

在 Prolog 谓词子句中,除非通过回溯和重新统一,否则不能更改变量

当您查询时,num(100, 200),从一开始 XY 分别被实例化为 100 和 200。那时,XY 的值现在可以 永远不会 在该谓词子句执行过程中改变。表达式 X is X + 1 总是 失败,因为 Prolog 将评估 X + 1 并确定它是否 X,这永远不可能是真的(在这种情况下,它总是将 100 与 101 进行比较)。

当您在 Prolog 中查询谓词时,例如 foo(A, B),它会寻找尚未设置的任何变量的值(它们是 未实例化的)使查询 true。如果它找到这样的值,它就会成功。如果找不到,则失败。如果您有一系列由连词 (,) 分隔的查询,例如 foo1(A), foo2(A),Prolog 首先查询 foo1(A),如果成功,将查询 foo2(A)。如果 foo2(A) 失败,Prolog 将 回溯 foo1(A) 并尝试使用 A *if A 的其他值使其为真在 foo1(A).

之前未实例化(未设置)

遍历整数范围

在您的作业中,您需要从一个整数迭代到另一个整数(在 num(X, Y) 查询中从 XY)。在没有回溯的情况下不能在 Prolog 中重新分配变量的限制如何做到这一点?在 Prolog 中有不止一种方法可以做到这一点。一种干净的方法是 CapelliC 展示的使用 between/3.

的方法
num(X, Y) :-
    % `between` will first instantiate N with X.
    % On backtracking, it will instantiate N with successive values
    % and succeed until the value exceeds Y. Then it will fail.
    %
    between(X, Y, N),
    <do some calls with N, write out successful values>,
    fail.                  % Automatically backtrack here

另一种方式是递归:

num(X, Y) :-
    % NOTE: if X and Y are given, then their values CANNOT BE CHANGED
    % in this predicate clause!
    %
    X =< Y,                % num(X, Y) succeeds only if X =< Y
    <do some calls with X and/or Y, write successful values>,
    NextX is X + 1,     % New variable whose value is X + 1
    num(NextX, Y).

递归将继续,直到 num 看到 X 大于 Y 并最终失败。

Prolog "if-else"构造

当你想做一个 if 构造时,你需要加上括号以考虑运算符的优先级:

(   <test>
->  <something 1>,         % if test succeeds
    ...
    <something N>
;   <something else 1>,
    ...
    <something else M>
)

如果您只想在 "else" 案例上取得成功,而不是 "something else",只需 true:

(   <test>
->  <something 1>,         % if test succeeds
    ...
    <something N>
;   true
)

生成结果

以上示例仍然使用您的 write 方法向用户显示结果。这并不是真正在 Prolog 中执行此操作的规范方法。更好的方法是定义一个谓词,例如 num(X, Y, R),它将连续提供 R 的值,使其在回溯时为真。这是对上述案例的一个小修改:

num(X, Y, R) :-
    % `between` will first instantiate N with X.
    % On backtracking, it will instantiate N with successive values
    % and succeed until the value exceeds Y. Then it will fail.
    %
    between(X, Y, R),
    <do some calls with R>.   % Succeed if R passes criteria

num(X, Y, X) :-
    % NOTE: if X and Y are given, then their values CANNOT BE CHANGED
    % in this predicate clause!
    %
    X =< Y,                % num(X, Y) succeeds only if X =< Y
    <do some calls with X and/or Y>.    % Succeed if X passes criteria
num(X, Y, R) :-
    X < Y,
    X1 is X + 1,
    num(X1, Y, R).

然后每个回溯产生每个结果:

?- num(100,200,R).
R = 105 ;
R = 114 ;
...
false.