Reaching end of list in prolog

2019-06-21 08:24发布

I've been given the question:

Define a predicate ordered/1, which checks if a list of integers is correctly in ascending order. For example, the goal ordered([1,3,7,11]) should succeed, as should the goal ordered([1,3,3,7]), whereas the goal ordered([1,7,3,9]) should fail.

So far I have this:

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

But it fails on every list.

I have deduced that the reason it fails is because it reaches the end number in the list then tries to compare that number against an empty list. Obviously this fails because you can't compare an integer to an empty list. Even if you could and it, say, returned 0 for an empty list, it would still return false as the number would be greater than 0, not less than.

I can't find a solution... Any ideas? Thanks, Jon.


Edit

So, some slightly amended code:

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

This now works for ordered([1]), but bigger lists still don't run correctly.

Should I include something like ordered([N, M|Ns]) in the definition?

7条回答
爷的心禁止访问
2楼-- · 2019-06-21 09:02

Don't use append/3.

edit1 to satisfy @false. In order to make it tail recursive friendly it has to eliminate backtracking. This is tail-recursive and only slight variation on @Xonix:

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

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

edit2 Take it a step further to eliminate lists that have less than two elements

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

ordered([X,Y|Ys]) :- 
    X =< Y,
    !,
    ordered([Y|Ys]).
查看更多
登录 后发表回答