使用Prolog从数字倒数

时间:2014-12-01 12:58:19

标签: prolog failure-slice

琐碎的问题,但我希望程序返回小于或等于给定数字的数字列表。例如,CountD(4,L)。应该给[4,3,2,1]。这就是我到目前为止所做的:

CountD(1,[]).
CountD(Num,List):- [Num|List], CountD(M,List), Num is M+1.

3 个答案:

答案 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的优点在于,虽然它的实际控制流程非常复杂,但通常只需查看程序的一小部分即可确定某些属性。因此,没有必要“立刻理解一切”。

我将采取以下

,而不是查看所有内容
countD(0,[]) :- false.
countD(Num,List) :-
   List = [Num|L],
   countD(M,L), false,
   Num is M+1.

在第一行中,通过在事实中插入 false ,有效地消除了这一事实。因此无论它准确描述什么,01都不会对此谓词的终止产生任何影响。通常,任何故障切片的非终止意味着原始程序不会终止。

当然,我们必须找到合适的切片。这是一点经验。但一旦发现,它的终止特性很容易检查。

为了解决这个问题,我们可以立即说,添加另一个子句不会改善终止(假设程序是纯粹的,单调的)。我们需要在可见部分改变一些东西。 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,[]).