琐碎的问题,但我希望程序返回小于或等于给定数字的数字列表。例如,CountD(4,L)
。应该给[4,3,2,1]
。这就是我到目前为止所做的:
CountD(1,[]).
CountD(Num,List):- [Num|List], CountD(M,List), Num is M+1.
答案 0 :(得分:4)
这也是一个解决方案:
countd(N, [N|List0]) :-
succ(N0, N),
countd(N0, List0).
countd(0, []).
此处,重要的一行是succ(N0, N)
。这仅对N>成功。 0,当第二个参数为0时将失败(如果N不是非负整数,它也会引发错误)。
当succ(N0, N)
失败时,将评估第二个子句。它只有在参数为0且为空列表时才会成功。
答案 1 :(得分:4)
@Boris'answer是完美的。我想解释一下,为什么你的原始程序和another answer的程序不会终止。
乍一看,它似乎有效,毕竟我们得到了答案:?- countD(4,L).
L = [4, 3, 2, 1]
但请注意,Prolog只向我们展示了第一个答案,还有更多,等待......
?- countD(4,L).
L = [4, 3, 2, 1] ;
**LOOPS**
了解Prolog终止的最佳方法是专注于程序的相关部分。 Prolog的优点在于,虽然它的实际控制流程非常复杂,但通常只需查看程序的一小部分即可确定某些属性。因此,没有必要“立刻理解一切”。
我将采取以下failure-slice:
,而不是查看所有内容countD(0,[]) :- false. countD(Num,List) :- List = [Num|L], countD(M,L), false,Num is M+1.
在第一行中,通过在事实中插入 false
,有效地消除了这一事实。因此无论它准确描述什么,0
或1
都不会对此谓词的终止产生任何影响。通常,任何故障切片的非终止意味着原始程序不会终止。
当然,我们必须找到合适的切片。这是一点经验。但一旦发现,它的终止特性很容易检查。
为了解决这个问题,我们可以立即说,添加另一个子句不会改善终止(假设程序是纯粹的,单调的)。我们需要在可见部分改变一些东西。 Boris通过在实际递归之前添加Num
的一些检查来做到这一点。
答案 2 :(得分:0)
countD(0,[]).
countD(Num,List) :- List = [Num|L], countD(M,L), Num is M+1.
<强>更新:强>
修复了@false和@boris在评论中发现的问题:
countD(Num,[Num|L]) :- Num > 0, M is Num-1, countD(M,L).
countD(0,[]).