2012-08-24 51 views
1

我大新手Prolog的,我试着写简单的发电机,发现下面5简单的Prolog发电机

gen(0). 
gen(X):- X<5 

的整数。当我运行根(X)的程序只打印X = 0并提示我输入内容,当我按下输入键后,再次显示'? - '。

如何让他从零到五生成数字?我正在使用SWI-Prolog。谢谢

回答

2

致力于枚举整数的内建谓词介于(低,高,数)之间。

使用,你会写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) 
+0

这就是我撞我现在跟着。我设法通过我自己创建了一个参数gen谓词,这与您提供的非常相似。而且我不知道为什么在通过X = 4时永远循环。 –

+1

@DimitarTsonev因为它会继续尝试,有6和7等等。要明白为什么,请暂时移除测试'X <5'。 'X <5'只是阻止它报告这些值,并说要继续尝试,就像我们在REPL按';'时一样。 –

+0

我想我错过了一些非常基本的东西。我那种情况下,如何告诉他在达到5时停止? –

-1

如何使用内置功能numlist

?- numlist(0,4,X). 
X = [0, 1, 2, 3, 4]. 
+0

没有什么要求,贝尔巴托夫号码列表,至少成员(Y,X)应遵循... – CapelliC

3

如果你不想使用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的第一个子句成功,当输入数字低于顶部时,将输出数字与输入数字绑定。

第二个子句递增当前数字并递归调用自身以在回溯时获得下一个数字。

2

好吧,因为gen/1应该生成从0到5的整数(从技术上讲,如果它是整数波节5 w Ë应该产生负面太),你可以这样做:

gen(0). 
gen(1). 
gen(2). 
gen(3). 
gen(4). 
gen(5). 

这在技术上满足焯芬的限制的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仅仅是速度的提高;请注意,如果我们更改最大数量,我们应该重新启动虚拟机。另一种选择是避免编译g/1并添加retract_all(g(_)),然后再调用generate/1。当然,显而易见的问题是它不是纯粹的序言,因为我们依赖于元谓语。

良好,所有这些限制似乎不可能确实