在prolog中到达列表的末尾

时间:2009-08-26 12:29:05

标签: list recursion prolog

我被问到了这个问题:

  

定义谓词ordered / 1,它检查整数列表是否按升序正确。例如,目标ordered([1,3,7,11])应该成功,目标ordered([1,3,3,7])应该成功,而目标ordered([1,7,3,9])应该失败。

到目前为止,我有这个:

ordered([]).    
ordered([N, M|Ns]):-
    append(M, Ns, Tail),
    ordered(Tail),
    N =< M.

但它在每个列表上都失败了。

我已经推断出它失败的原因是因为它到达列表中的结束号然后尝试将该数字与空列表进行比较。显然这会失败,因为您无法将整数与空列表进行比较。即使你可以,也就是说,它返回0作为一个空列表,它仍然会返回false,因为该数字将大于0,而不是小于。{/ p>

我找不到解决方案......有什么想法吗?谢谢,乔恩。


修改

所以,稍微修改了一些代码:

ordered([]).
ordered([N]):-
    N >= 0.
ordered([N, M|Ns]):-
    append(M, Ns, Tail),
    ordered(Tail),
    N =< M.

现在适用于ordered([1]),但较大的列表仍然无法正常运行。

我应该在定义中包含ordered([N, M|Ns])这样的内容吗?

7 个答案:

答案 0 :(得分:5)

(假设这是作业,我不愿意提供完整的解决方案)。

查看您的代码,尝试了解它如何统一?- ordered([1]). 精神上运行此查询(或使用trace / 0),查看它的作用,一步一步,以及它如何计算结果。

此外,在思考prolog时,请尽量让“重新获得价值”。 Prolog谓词不会返回任何内容。

答案 1 :(得分:2)

我认为您的解决方案也不是尾递归。 想想会有这样的事情:

ordered([]) :-!.
ordered([_]):-!.
ordered([A,B|T]) :-
    A =< B,
    !,
    ordered([B|T]).

答案 2 :(得分:2)

如果您的Prolog系统支持,请检查它是否提供了库谓词clpfd:chain/2

:- use_module(library(clpfd)).

如果是这样,只需写下:

?- chain([1,3,7,11],#<).
true.

?- chain([1,3,3,7],#=<).
true.
?- chain([1,3,3,7],#<).
false.

?- chain([1,7,3,9],#<).
false.

答案 3 :(得分:2)

如果您使用SICStus Prologmy previous answer不起作用 clpfd library in SICStus Prolog  不提供库谓词 chain/3包括在内 SWI-Prolog's clpfd library

# for 3 dimensions [0,1,2] and direction == 1 --> [1, 0, 2]
tr = [direction] + range(A.ndim)
del tr[direction+1]

return np.transpose(A, tr)[idx]
不要惊慌!只需像这样实现谓词:- use_module(library(clpfd)). :- assert(clpfd:full_answer).

ordered/1

让我们在SICStus Prolog 4.3.2中看到它。 这是最常见的查询:

ordered([]).
ordered([X|Xs]) :- 
   ordered_prev(Xs,X).

ordered_prev([]     ,_ ).
ordered_prev([X1|Xs],X0) :- 
   X0 #=< X1,
   ordered_prev(Xs,X1).

以下是OP建议的查询:

?- ordered(Xs).
  Xs = []
; Xs = [_A]
; Xs = [_A,_B],    _A#=<_B,          _A in inf..sup, _B in inf..sup
; Xs = [_A,_B,_C], _A#=<_B, _B#=<_C, _A in inf..sup, _B in inf..sup, _C in inf..sup
... % an infinity of solutions follows: omitted for the sake of brevity.

请注意,上面示例中的两个后续查询都没有留下任何无用的选择点,这要归功于第一个参数索引。

答案 4 :(得分:1)

你说得对:根据你的代码,列表只有两种可能的方式ordered

  1. 它是空的
  2. 前两项的顺序正确,列表的其余部分为ordered
  3. 这些肯定都是正确的陈述,但列表[3]怎么样?那不是ordered吗?显然,只有一个元素的列表是有序的,但你没有表达它的条款:它既不适合你的基本情况也不适合你的递归情况。

    单元素列表是隐藏在此处尚未解决的另一个案例。由于这与您已定义的两个规则无关,因此您可能需要考虑单独解决此特殊情况的方法。

答案 5 :(得分:0)

嗯,最后,很容易修复。

这是正确的代码。

ordered([]).

ordered([N, M|Ns]):-
 append([M], Ns, Tail),
 ordered(Tail),
 N =< M.

ordered([M]).

有序([M])。处理如上所述的单元素列表。

我的问题的真正根源是在追加函数中的M周围不包括[]。

关于授予正确答案的礼节是什么?你们都非常有帮助。

乔恩

答案 6 :(得分:0)

请勿使用append/3

edit1 以满足@false。为了使尾部递归友好,它必须消除回溯。这是尾递归的,@ Xonix只有轻微的变化:

ordered([X|[]]):-!.

ordered([X,Y|Ys]) :- 
    X =< Y,
    !,
    ordered([Y|Ys]).

edit2 更进一步消除少于两个元素的列表

ordered([X,Y|[]]):- X =< Y,!.

ordered([X,Y|Ys]) :- 
    X =< Y,
    !,
    ordered([Y|Ys]).