The mode indicator seems wrong
The mode indicator +
in is_list(+Term)
says that Term should not be an unbound variable but some term following a minimal specification. But is_list/1 survives that in any case.
It would be better to have
is_list(@Term)
Argument will not be further instantiated than it is at call-time. Typically used for type tests.
That's exactly what is needed.
Some simple unit tests for this predicate
Checking whether we have an open list
For list terminology, see the glossary
An open list has a "empty cell" at the last position of the list backbone
List1 = [1,2,3|[]] % a "proper" (or "closed") list List2 = [1,2,3] % exactly the same as List1 OpenList = [1,2,3|_] % open list: an unbound (even an anonymous) variable at Fin OpenList = [1,2,3|Fin] % open list with an unbound non-anonymous variable at Fin OpenList = _ % limiting case: an open list with any listcell. a bit dubious
is_list/1 says no in those cases:
?- is_list(_). false. ?- is_list([1,2,3|_]). false.
Actually, the mode indicator +
in is_list(+Term)
says that Term should not be an unbound variable but some term following a minimal specification. But is_list/1 survives that in any case.
- proper/closed list on the left
- open list on the right
List ------->[|] [|]<-------------- OpenList / \ / \ 1 [|] 1 [|] / \ / \ 2 [|] 2 [|] / \ / \ 3 [] 3 ~empty cell~ <--- Fin
How about a new is_list/2 then?
There is a Big Problem with Prolog inherent in untyped unbound variables. They could become anything. But: at the moment we check what they are, we just don't know whether we are supposed to succeed or fail.
is_list(_)
fails - but that's a statement about THE STATE OF THE COMPUTATION, not about the anonymous variable _. It is completely non-logical.
If an X could be "typed as a list" and is_list(X)
failed with that typed X one could at least have a logical interpretation... `X is not now, and can never be, a list`.
Okay. So, how about a new is_list/2 then?
One that works like this:
It always succeeds with an unbound What but reifies the truth value into What so you can perform an acceptance/verification
is_list(+Term,-What)
with the following truth table:
% --- % is_list(@Term,?What) % --- % % % +----------------------------------------------+ % | accepted as What | % +-----------+--------+---+----+-----+------+-------+-------+ % | generated | true |var|open|false|oclist|voclist|canlist| % | as What | closed | | | | | | | % | | proper | | | | | | | % +---------+-----------+--------+---+----+-----+------+-------+-------+ % | [] | true | x , , , , x , x , | % | [a,b,c] | true | x , , , , x , x , | % | _ | var | , x , , , , x , x | % | [a,b|_] | open | , , x , , x , x , x | % | [a,b|x] | false | , , , x , , , | % | foo | false | , , , x , , , | % +---------+-----------+----------------------------------------------+
- "oclist" stands for "open or proper list (but not unbound variable)"
- "voclist" stands for "open or proper list or unbound variable"
- "canlist" stands for "not currently a proper list but can become one as it's an open list or an unbound variable"
- when accepting, one can use
closed
orproper
instead oftrue
Example:
?- is_list([a,b,c],W). W = true.
Term designates a closed/proper list. This is a strong logical statement: Term is a list now and this will stay so in the future.
?- is_list([a,b|_],W). W = open. ?- is_list(_,W). W = var. ?- is_list(_,open). false. % actual failure
Term designates an open list with at least one listcell, i.e. is not an unbound variable. This is a statement about the state of the computation: Term is (the start of an) open list now but this may change in the future: the structure may become a closed list, stay an open list, or become a non-list. We really don't know.
?- is_list(_,W). W = var.
Term is an unbound variable and we REALLY DON'T KNOW ANYTHING ELSE. This is a statement about the state of the computation: Term may become a closed list, a closed list with at least one listcell, may stay unbound or become something else. It may even be an empty open list "in the mind of the programmer" now (being an unbound variable), we don't have insight into that.
?- is_list(foo,W). W = false.
Again, a strong logical statement: Term is not a proper list, not an open list of at least one listcell, not an unbound variable. It is "something else" with information content. So we can say "false" (but not fail).
And so: source code