Content Summary
This chapter focuses on a practical example of using a recursive manipulation list: Determining whether an element is contained in a list.
It's time to introduce the example of a program in the first Prolog that uses a recursive manipulation list. One of the things that interests us most is whether an object is an element in a list. So, we want to write a program that when assumed input is an object x and a list L,
The result is whether x belongs to L. The name of this program is usually: member, which is the simplest example of using a recursive manipulation list in a Prolog program, as follows:
Member (X, [x| T]).
Member (X, [h| T]):-Member (X, T).
This is the whole code: a fact (that is, member (X, [x| T]) and a rule (that is, member (X, [h| T]):-Member (X, T)). Note, however, that this rule is recursive (because functor: member also appears at the head of the rule and
Trunk), it can explain why such a short program can meet the requirements and let us analyze it further.
First of all, we interpret this procedure from a declarative perspective. Through this interpretation, it will be found to be completely meaningful. The first clause, the fact, simply says that if Object X is the head of a list, then x is the element of the list. Please note that we have used
Built-in "|" operator to manipulate the list.
So what about the second recursive clause? It means that if object X is an element at the end of a list, it is also an element of the list. Also note the use of the "|" Operator action list.
Now, it is clear that this definition has a very good declarative meaning. But will this program run like it does with declarative meaning? That is, is the program really able to find out if an object x is an element of a list l? If so, how is it done?
To answer these questions, we need to think about the procedural implications. Let's get the results through the following simple sample.
Suppose we make the following query:
?-member (Yolanda, [Yolanda, Trudy, Vincent, Jules]).
Prolog will immediately answer true. Why? Because the program uses the first clause (that is, the fact) to combine Yolanda and X, the answer is given immediately.
Next, consider the following query:
?-member (Vincent, [Yolanda, Trudy, Vincent, Jules]).
Now the first sentence cannot provide an answer (Vincent and Yolanda are different atoms), so Prolog continues to use the clause of the second recursive rule, which gives a new target:
Member (Vincent, [Trudy, Vincent, Jules]).
Now that the first sentence cannot provide the answer again, Prolog continues to use the clause of the second recursive rule, which gives a new goal:
Member (Vincent, [Vincent, Jules]).
This time, the first clause will provide an answer, and the query will succeed.
It's all OK, but we need to ask an important question, what happens if our query fails? For example, if you are querying:
Member (Zed, [Yolanda, Trudy, Vincent, Jules]).
Now, this query obviously fails (after all, Zed is not in the list). So how does Prolog deal with it? In particular, how do we make sure that Prolog terminates and returns false instead of being stuck in a recursive infinite loop?
Let's answer this question through systematic thinking. Again, the first clause fails to provide an answer, so Prolog uses a recursive rule that gives a new goal:
Member (Zed, [Trudy, Vincent, Jules])
Similarly, the first clause cannot provide an answer, so Prolog uses recursion rules and gives a new goal:
Member (Zed, [Vincent, Jules])
Similarly, the first clause cannot provide an answer, so Prolog uses recursion rules and gives a new goal:
Member (Zed, [Vincent])
Now the first sentence is still unable to provide an answer, so Prolog uses recursive rules and gives new goals:
Member (Zed, [])
Now when it comes to fun, the obvious first sentence still fails to provide an answer. Note, however, that recursion rules don't work, why? Simple: Recursive rules rely on decomposing lists into heads and tails, as we saw earlier,
An empty list can no longer be split in this way. So the recursive rules don't work anymore, so Prolog stopped searching for further solutions and reported false. That is, Prolog tells us that Zed does not belong to this list, and that is exactly what we expect
The answer.
We can summarize the predicate logic of MEMBER/2: It is a recursive predicate logic that will systematically traverse the entire list to search for answers. It breaks down the list into smaller lists, and searches the head of every smaller list to
With. This method causes the search to be recursive, and because the recursion is secure (because it does not fall into an infinite loop), the final prolog must involve an empty list. Empty lists can no longer be decomposed into smaller lists, so it is possible to end recursive recursion.
Well, we now fully understand how MEMBER/2 works, but in fact, this predicate logic is far more useful than the previous example. We just used it to answer some examples of true/false, but we were able to use variables in our queries,
For example, if we make a query:
?-Memeber (X, [Yolanda, Trudy, Vincent, Jules]).
X = Yolanda;
X = Trudy;
X = Vincent;
X = Jules;
False
That is, Prolog has told us a list of each element, which is MEMBER/2 a particularly common way to use. Essentially, through variables, we can ask Prolog: "Quick!" Give me some elements of this list! ”。 In a lot of
Application we need to get the elements from the list, which is a typical approach.
Finally, the way we define MEMBER/2 is correct, but a bit redundant.
Imagine that the first clause deals with the head of the list, although the tail of the list is irrelevant in the first clause, but we still use the variable t to unite it. Similarly, the recursion rule handles the tail of the list, although the head of the list
is a irrelevant , but we still use the variable h to unite it. These unnecessary variables can be excluded: if the definition of predicate logic concentrates on the concepts we care about, and irrelevant information is treated with anonymous variables, it is a better way to define them.
For example, we The following refactoring is performed on the MEMBER/2:
Member (x, [x | _]).
Member (X, [_ | T]):-Member (X, T).
This version is both declarative and procedural in the same way as the first version. But the definition of this version is clearer: When you read it, you focus on the nature of the problem.
Learn Prolog now Translations-fourth chapter-List-section II, List members