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 goalordered([1,3,3,7])
, whereas the goalordered([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?
I think your solution is not also tail-recursion-friendly. Think something like that would do:
If your Prolog system supports clpfd, check if it offers the library predicate
clpfd:chain/2
.If so, simply write:
If you are using SICStus Prolog, my previous answer will not work, as the clpfd library in SICStus Prolog does not offer the library predicate
chain/3
included with SWI-Prolog's clpfd library.Don't panic! Simply implement predicate
ordered/1
like this:Let's see it in action with SICStus Prolog 4.3.2. Here's the most general query:
And here are the queries the OP suggested:
Note that both succeeding queries in above example did not leave any useless choicepoints behind, thanks to first argument indexing.
Well that, in the end, was rediculously easy to fix.
Here is the correct code.
ordered([M]). deals with the single-element list as described above.
The real root of my problem was not including [] around the M in the append function.
Whats the ettiquette regarding awarding the correct answer? You've both helped muchly.
Jon
(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.
You're quite right: according to your code there are only two possible ways a list can be
ordered
:ordered
Those are certainly both correct statements, but what about the list
[3]
? Isn't thatordered
too? Obviously a list with only one element is ordered, yet you have no provision for expressing that: it fits neither your base case nor your recursive case.The single-element list is another case hiding here that you haven't addressed yet. Since this is independent of the two rules you've already defined, you might want to consider a way to address this special case separately.