Determining if a list is empty or not

2019-08-12 15:16发布

问题:

I want to do some if | else stuff in prolog. Below is my code, Prolog will return 'R = false' if my input list is not empty, it will return 'false' if my list is empty. What do I miss?

Code:

isEmpty([H|T],R) :- 
    length([H|T],L),
    ( L > 0 -> R = 'false'
    ;
    L =:= 0 -> R = 'true'
    ).

Prolog Output:

1 ?- isEmpty([],R).
false.

2 ?- isEmpty([1],R).
R = false.

3 ?- isEmpty([1,2,3],R).
R = false.

回答1:

One way to define this would be to use unification ("pattern matching"):

list_empty([], true).
list_empty([_|_], false).

If you insist on using an if-then-else, you need to pass the list without trying to match it in any way:

list_zerolength(List, Empty) :-
    length(List, Len),
    (   Len == 0
    ->  Empty = true
    ;   Empty = false
    ).

... but this is not optimal. The two predicates behave identically if the first argument is indeed a list:

?- list_empty([], R).
R = true.

?- list_empty([_], R).
R = false.

?- list_zerolength([], R).
R = true.

?- list_zerolength([_], R).
R = false.

However, something annoying happens if the first argument is not ground (that is, is not fully instantiated):

?- list_zerolength(L, true).
L = [] ;
ERROR: Out of global stack

So, we try to ask for an empty list, and we get it; however, Prolog insists there might be another answer. When we try to get it, we get an error.

(Extra credit: figure out what happens!)

The predicate list_empty/2 is not perfect, either. Consider:

?- list_empty([_|a], R).
R = false.

This succeeds, and we could interpret the answer as: "The list [_|a] is not empty". However, this is not ever a proper list!

?- is_list([_|a]).
false.

Using length/2 is not at all a bad idea. We can use it to write a predicate that is arguably a bit more useful than list_empty/2. I call it list_nonempty/2 to confuse the situation:

list_nonempty([], false).
list_nonempty([_|T], true) :-
    length(T, _).

length/2 does a lot more than just finding the length of a list. It can be used to generate lists of increasing length, or check whether its first argument is a proper list:

?- list_nonempty(L, NE).
L = [],
NE = false ;
L = [_G904],
NE = true ;
L = [_G904, _G907],
NE = true . % and so on

?- list_nonempty(L, false).
L = [].

?- list_nonempty([], true).
false.

?- list_nonempty([_|a], true).
ERROR: length/2: Type error: `list' expected, found `a' (an atom)

SWI-Prolog throws an error when length/2 is not given a list. Implementations that are more committed to ISO-compliance should fail instead. With GNU Prolog:

?- list_nonempty([_|a], true).    
no


回答2:

I know it's old thread but still this might be useful for those using SWI-Prolog. Instead of defining their own rules, you can try:

nth0(0, List, _).

It is used to return the first element on the list, which in case of empty list simply fails.



回答3:

Since you are only dealing with lists of the form [H|T] your clauses will only match for lists that have at least one list element. In other words, you get the answer false for the empty list because there is not a matching clause - not because the length is 0.



标签: list prolog