3

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

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

3 回答 3

4

这也是一个解决方案:

countd(N, [N|List0]) :-
    succ(N0, N),
    countd(N0, List0).
countd(0, []).

在这里,重要的一行是succ(N0, N)。这只会在 N > 0 时成功,并且在第二个参数为 0 时会失败(如果 N 不是非负整数,它也会引发错误)。

失败时succ(N0, N),将评估第二个子句。只有当它的参数为 0 和空列表时它才会成功。

于 2014-12-01T14:17:35.653 回答
4

@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事实,事实被有效地删除。所以无论它具体描述什么,0or1对这个谓词的终止没有任何影响。一般来说,不终止任何故障片意味着不终止原始程序。

当然,我们必须找到正确的切片。这是一点经验。但是一旦找到它,它的终止属性就很容易检查。

为了解决这个问题,我们可以立即说添加更多子句不会改善终止(假设程序是纯粹的、单调的)。我们需要更改可见部分的某些内容。NumBoris 通过在实际递归之前添加一些检查来做到这一点。

于 2014-12-01T21:48:23.847 回答
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,[]).
于 2014-12-01T20:58:31.660 回答