Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reaching end of list in prolog

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?

like image 316
JonB Avatar asked Aug 26 '09 12:08

JonB


People also ask

How do you find the last element of a list in Prolog?

You just want the last element of the list. Try this: lastElement([Head]) :- write(Head). lastElement([_|Tail]):- lastElement(Tail).

How do you append in Prolog?

One important use of append/3 is to split up a list into two consecutive lists. For example: ?- append(X,Y,[a,b,c,d]). That is, we give the list we want to split up (here [a,b,c,d] ) to append/3 as the third argument, and we use variables for the first two arguments.

How do you select an element in a list in Prolog?

This predicate can be used to select an element from a list, delete an element or insert it. The definition of this Prolog library predicate is: select(A, [A|B], B). select(A, [B, C|D], [B|E]) :- select(A, [C|D], E).


2 Answers

(assuming this is homework, I hesitate to give a complete solution).

Looking at your code, try to find out how it would unify ?- ordered([1]). Run this query mentally (or using trace/0) and see what it does, step by step, and how it computes its result.

Also, please try to get "returns a value" out of your mind when thinking prolog. Prolog predicates don't return anything.

like image 88
Martin v. Löwis Avatar answered Sep 28 '22 08:09

Martin v. Löwis


I think your solution is not also tail-recursion-friendly. Think something like that would do:

ordered([]) :-!.
ordered([_]):-!.
ordered([A,B|T]) :-
    A =< B,
    !,
    ordered([B|T]).
like image 40
Volodymyr Gubarkov Avatar answered Sep 28 '22 06:09

Volodymyr Gubarkov