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