坚持序言程序
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)
,从一开始 X
和 Y
分别被实例化为 100 和 200。那时,X
和 Y
的值现在可以 永远不会 在该谓词子句执行过程中改变。表达式 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)
查询中从 X
到 Y
)。在没有回溯的情况下不能在 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.
所以我遇到了我的 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)
,从一开始 X
和 Y
分别被实例化为 100 和 200。那时,X
和 Y
的值现在可以 永远不会 在该谓词子句执行过程中改变。表达式 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)
查询中从 X
到 Y
)。在没有回溯的情况下不能在 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.