我是 Prolog 的新手,我正在尝试编写简单的生成器,它可以找到低于 5 的整数。
gen(0).
gen(X):- X<5
当我使用 gen(X) 运行程序时,它只打印 X = 0 并提示我输入一些内容,当我按下 enter 时,'?-' 再次显示。
如何让他生成从零到五的数字?我正在使用 SWI-Prolog。谢谢
如果您不想使用between/3
,可以使用辅助程序轻松编写生成器gen/3
:
gen(Num):-
gen(0, 5, Num).
gen(Cur, Top, Cur):- Cur < Top.
gen(Cur, Top, Next):-
Cur < Top,
succ(Cur, Cur1), % or Cur1 is Cur+1
gen(Cur1, Top, Next).
辅助过程gen/3
跟踪当前生成的编号和顶部编号,并将第三个参数与当前生成的编号绑定。
的第一个子句gen/3
成功,当输入数低于顶部时,将输出数与输入数绑定。
第二个子句增加当前数字并递归调用自身以在回溯时获取下一个数字。
用于枚举整数的内置谓词介于 (Low,High,Num) 之间。
使用它你会写gen(X) :- between(0,4,X).
我已经以这种方式重新实现了
gen(X) :- between_(0, 4, X).
/* between_(I,J,K) is true if K is an integer between I and J inclusive. */
between_(I,J,I) :- I =< J.
between_(I,J,K) :- I < J, I1 is I+1, between_(I1,J,K).
问题的有趣部分是理解为什么只有一个参数的天真实现永远循环......
gen(0).
gen(X) :- gen(Y), X is Y + 1, X < 5.
?- gen(X).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
^CAction (h for help) ? goals
[374,153] 3<5
[374,152] gen(3)
[374,151] gen(_G1013)
[374,150] gen(_G1013)
[374,149] gen(_G1013)
好吧,因为 gen/1 应该生成从 0 到 5 的整数(从技术上讲,如果它是低于 5 的整数,我们也应该生成负数)你可以这样做:
gen(0).
gen(1).
gen(2).
gen(3).
gen(4).
gen(5).
这在技术上满足了 chack 的限制 xD
gen/2
对于第一个参数定义我们可以做的最大数量的谓词:
gen(N,R):-
N>0,
R is N-1.
gen(N,R):-
N>1,
NN is N-1,
gen(NN,R).
但这具有使用第一个参数的优点。避免第一个解决方案的规则改写是,我们应该能够在不更改规则的情况下用其他数字替换每次出现的 5,并且程序应该仍然可以工作;我们还应该补充一点,我们不能使用列表(除非它们正好有 1 个元素)或元组或基本上任何具有两个变量作为参数的术语以及任何类型的编码(例如2^X
* )。3*Y
受第一个程序的启发:
gen(X):-
clause(g(_),_) ->
g(X) ; (generate(5),!, g(X)).
generate(-1):-
compile_predicates([g/1]).
generate(N):-
assert(g(N)),
NN is N-1,
generate(NN).
compile_predicates/1
只是为了提高速度;请注意,如果我们更改最大数量,我们应该重新启动 VM。另一种选择是避免编译并在我们调用之前g/1
添加 a 。当然,明显的问题是它不是纯粹的序言,因为我们依赖元谓词。retract_all(g(_))
generate/1
好吧,有了所有这些限制,这似乎确实是不可能的
使用内置功能numlist
怎么样?
?- numlist(0,4,X).
X = [0, 1, 2, 3, 4].