14.7 Going Further in Prolog

14.7.1 Program Control in Prolog: A Binary Tree Example

The following set of facts describes a binary tree (lines 2–3). A path predicate is also included that defines a path between two vertices, with two rules, to be either an edge from X to Y (line 6) or a path from X to Y (line 7) through some intermediate vertex Z such that there is an edge from X to Z and a path from Z to Y:

A set of seven code lines in Prolog with a path predicate.
Description

Notice that the comma in the body (i.e., right-hand side) of the rule on line 7 represents conjunction. Likewise, the :- in that rule represents implication. Thus, the rule path(X,Y) :- edge(X,Z), path(Z,Y) is the Prolog equivalent of the Horn clause path(X, Y) ⊂ edge(X, Z)∧ path(Z, Y). The user can then query the program by expressing goals to determine whether the goal is true or to find all instantiations of variables that make the goal true. For instance, the goal path(b,c) asks if there exists a path between vertices b and c:

A set of three code lines in Prolog with a goal.
Description

To prove this goal, Prolog uses resolution, which involves unification. When the goal path(b,c) is given, Prolog runs its resolution algorithm with the following steps:

A set of three code lines in Prolog that proves a goal.
Description

During resolution, the term(s) in the body of the unified rule become subgoal(s). Consider the goal path(X,c), which returns all the values of X that satisfy this goal:

A set of five code lines in Prolog with a goal.
Description

Prolog searches its database top-down and searches subgoals from left-to-right during resolution; thus, it constructs a search tree in a depth-first fashion. A top-down search of the database during resolution results in a unification between this goal and the head of the rule on line 6 and leads to the new goal: edge(X, c). A proof of this new goal leads to additional unifications and subgoals. The entire search tree illustrating the resolution process is depicted in Figure 14.2. Source nodes in Figure 14.2 denote subgoals, and target nodes represent the body of a rule whose head unifies with the subgoal in the source. Edge labels in Figure 14.2 denote the line number of the rule involved in the unification from subgoal source to body target.

An illustration of a search tree for the resolution process used to satisfy the goal.

Figure 14.2 A search tree illustrating the resolution process used to satisfy the goal path(X,c).

Modified from Louden, K. C., and K. A. Lambert. 2011. Logic Programming. In Programming Languages: Principles and Practices. Boston, MA: Cengage Learning.

Description

Modified from Louden, K. C., and K. A. Lambert. 2011. Logic Programming. In Programming Languages: Principles and Practices. Boston, MA: Cengage Learning.

Notice that satisfaction of the goal edge(X,c) involves backtracking to find alternative solutions. In particular, the solution X=b is found first in the left subtree and the solution X=a is found second in the right subtree. A source node with more than one outgoing edge indicates backtracking (1) to find solutions because searching for a solution in a prior subtree failed (e.g., see two source nodes in the right subtree each with two outgoing edges) or (2) to find additional solutions (e.g., second outgoing edge from the root node leads to the additional solution X=a).

Consider transposing the rules on lines 6 and 7 constituting the path predicate in the example database:

A set of two code lines in Prolog with a path predicate.
Description

A top-down search of this modified database during resolution results in a unification of the goal path(X, c) with the head of the rule on line 6 and leads to two subgoals: edge(X, Z), path(Z, c). A left-to-right pursuit of these two subgoals leads to additional unifications and subgoals, where the solution X=a is found before the solution X=b:

A set of four code lines in Prolog where the solution of X equals a is found before the solution of X equals b.
Description

The entire search tree illustrating the resolution process with this modified database is illustrated in Figure 14.3. Notice the order of the terms in the body of the rule path(X,Y) :- edge(X,Z), path(Z,Y). Left recursion is avoided in this rule since Prolog uses a depth-first search strategy. Consider a transposition of the terms in the body of the rule path(X,Y) :- edge(X,Z), path(Z,Y):

An illustration of an alternative search tree for the resolution process for satisfying the goal.

Figure 14.3 An alternative search tree illustrating the resolution process used to satisfy the goal path(X,c).

Description
A set of two code lines in Prolog consisting of transposition of the terms in the body.
Description

The left-to-right pursuit of the subgoals leads to an infinite use of the rule path(X,Y) :- path(Z,Y), edge(X,Z) due to its left-recursive nature:

A set of two code lines in Prolog with an infinite use of a rule.
Description
Continuation of the code in Prolog with error message, consisting of eight lines.
Description

Since the database is also searched in a top-down fashion, if we reverse the two rules constituting the path predicate, the stack overflow occurs immediately and no solutions are returned:

A set of two code lines, followed by five lines of error message in Prolog.
Description

The search tree for the goal path(X,c) illustrating the resolution process with this modified database is presented in Figure 14.4. Since Prolog terms are evaluated from left to right, Z will never be bound to a value. Thus, it is important to ensure that variables can be bound to values during resolution before they are used recursively.

An illustration of a search tree in which a goal, which is path X c, leads to path Z c and edge X Z through 6. Path Z c leads to path Z c and edge X Z through 6, and the process continues.

Figure 14.4 Search tree illustrating an infinite expansion of the path predicate in the resolution process used to satisfy the goal path(X,c).

Mutual recursion should also be avoided—to avert an infinite loop in the search, not a stack overflow:

A list of four code lines for averting an infinite loop in the search.
Description

In summary, the order in which both the knowledge base in a Prolog program and the subgoals are searched and proved, respectively, during resolution is significant. While the order of the terms in the antecedent of a proposition in predicate calculus is insignificant (since conjunction is a commutative operator), Prolog pursues satisfaction of the subgoals in the body of a rule in a deterministic order. Prolog searches its database top-down and searches subgoals left-to-right during resolution and, therefore, constructs a search tree in a depth-first fashion (Figures 14.214.4). A Prolog programmer must be aware of the order in which the system searches both the database and the subgoals, which violates a defining principle of declarative programming—that is, the programmer need only be concerned with the logic and leave the control (i.e., inference methods used to satisfy a goal) up to the system. Resolution comes free with Prolog— the programmer need neither implement it nor be concerned with the details of its implementation. The goal of logic/declarative programming is to make programming entirely an activity of specification—programmers should not have to impart control upon the program. On this basis, Prolog falls short of the ideal. The language Datalog is a subset of Prolog. Unlike Prolog, the order of the clauses in a Datalog program is insignificant and has no effect on program control.

While a depth-first search strategy for resolution is efficient, it is incomplete; that is, DFS will not always result in solutions even if solutions exist. Thus, Prolog, which uses DFS, is incomplete. In contrast, a breadth-first search strategy, while complete (i.e., BFS will always find solutions if any exist), is inefficient. However, Prolog and Datalog are both sound—neither will find incorrect solutions. Table 14.13 compares Prolog and Datalog.

Table 14.13 A Comparison of Prolog and Datalog

A table for sound, complete, and Turing complete of different languages.
Description

14.7.2 Lists and Pattern Matching in Prolog

The built-in list data structures in Prolog and the associated pattern matching are nearly identical syntactically to those in ML/Haskell (Table 14.14). However, ML/Haskell, unlike Prolog, support currying and curried functions and a powerful and clean type and module system for creating abstract data types. As a result, ML and Haskell are used in AI for applications where Prolog (or Lisp) may have once been the only programming languages considered.

Table 14.14 Example List Patterns in Prolog Vis-à-Vis the Equivalent List Patterns in Haskell

Prolog

Haskell

Semantics

[]

[]

an empty list

[X|Y]

X:Y

a list of at least one element

[X,Y|Z]

X:Y:Z

a list of at least two elements

[X,Y,Z|W]

X:Y:Z:W

a list of at least three elements

.(X, Y)

X:Y

 

[X]

X:nil

a list of exactly one element

[X,Y]

X:Y:nil

a list of exactly two elements

[X|Y,Z]

N/A

 

[X|Y|Z]

N/A

 

A list of 14 code lines consisting of lists.
Description
Continuation of the code with lists, that consists of 10 lines.
Description

Notice the declarative nature of these predicates. Also, be aware that if we desire to include data in a Prolog program beginning with an uppercase letter, we must quote the entire string (lines 3, 5–10, and 22); otherwise, it will be treated as a variable. Similarly, if we desire to use a variable name beginning with a lowercase letter, we must preface the name with an underscore (_) (line 13). Consider the following the transcript of an interactive session with this database:

A set of 84 code lines that is a transcript of an interactive session with a database.
Description
Continuation of the code that is a transcript of an interactive session with a database, consisting of 30 lines.
Description

Notice the use of pattern matching and pattern-directed invocation with lists in the queries on lines 67, 81, 96, and 103 (akin to their use in ML and Haskell in Sections B.8.3 and C.9.3, respectively, in the online ML and Haskell appendices). Moreover, notice the nature of some of the queries. For instance, the query on line 10 called a cross-product or Cartesian product. A relation is a subset of the Cartesian product of two or more sets. For instance, if A = {1, 2, 3} and B = {a, b}, then arelation RA × B = {(1, a), (1, b), (2, a), (2, b), (3, a), (3, b)}. The query on line 27 is also a Cartesian product, but one in which the pairs with duplicate components are pruned from the resulting relation.

14.7.3 List Predicates in Prolog

Consider the following list predicates using some of these list patterns:

A set of 10 code lines in Prolog with list predicates.
Description

Notice the declarative nature of these predicates as well as the use of pattern-directed invocation (akin to its use in ML and Haskell in Sections B.8.3 and C.9.3, respectively, in the online ML and Haskell appendices). The second fact (line 4) of the islist predicate indicates that a non-empty list consists of a head and a tail, but uses an underscore (_), with the same semantics as in ML/Haskell, to indicate that the contents of the head and tail are not relevant. The cons predicate accepts a head and a tail and puts them together in the third list argument. The cons predicate is an example of using an additional argument to simulate another return value. However, the fact cons(H,T,[H,T]) is just a declaration—we need not think of it as a function. For instance, we can pursue the following goal to determine the components necessary to construct the list [1,2,3]:

A set of four code lines for determining the components necessary to construct a list.
Description

Notice also that the islist and cons facts can be replaced with the rules islist([_|T]) :- islist(T). and cons(H,T,L) :- L = [H|T]., respectively, without altering the semantics of the program. The member1 predicate declares that an element of a list is either in the head position (line 9) or a member of the tail (line 10):

A set of 13 code lines in Prolog with the member 1 predicate.
Description

14.7.4 Primitive Nature of append

The Prolog append/3 predicate succeeds when its third list argument is the result of appending its first two list arguments. While append is built into Prolog, for purposes of instruction we define it as append1:

A set of five code lines in Prolog with the append 1 predicate.
Description

Notice that the fact on line 2 in the definition of the append1/2 predicate is superfluous since the rule on line 3 recurses through the first list only. The append predicate is a primitive construct that can be utilized in the definition of additional list manipulation predicates:

A set of six code lines in Prolog with the append predicate.
Description
Continuation of the code in Prolog with the append predicate.
Description

We redefine the member1 predicate using append1 (line 2). The revised predicate requires only one rule and declares that E is a element of L if any list can be appended to any list with E as the head resulting in list L:

A set of two code lines in Prolog with the predicate member 1.
Description

The sublist predicate (line 5) is defined similarly using append1. The reverse predicate declares that the reverse of an empty list is the empty list (line 8). The rule (line 9) declares that the reverse of a list [H|T] is the reverse of list T— the tail—appended to the list [H] containing only the head H. Again, notice the declarative style in which these predicates are defined. We use lists to define graphs and a series of graph predicates in Section 14.7.8. However, before doing so, we discuss arithmetic predicates and the nature of negation in Prolog since those graph predicates involve those two concepts.

14.7.5 Tracing the Resolution Process

Consider the following Prolog program:

A set of 16 code lines in Prolog for tracing the resolution process.
Description

To illustrate the assistance that the trace/0 predicate provides, consider determining the vertices along the path from vertex a to b:

A set of six code lines in Prolog with the trace predicate.
Description
Continuation of the code in Prolog with the trace predicate, consisting of 19 lines.
Description

This trace is produced incrementally as the user presses the ăenterą key after each line of the trace to proceed one step deeper into the proof process.

14.7.6 Arithmetic in Prolog

Since comparison operators (e.g., < and >) in other programming languages are predicates (i.e., they return true or false), such predicates are generally used in Prolog in the same manner as they are used in other languages (i.e., using infix notation). The assignment operator in Prolog—in the capacity that an assignment operator can exist in a declarative style of programming—is the is predicate in Prolog:

A set of six code lines in Prolog with the is predicate.
Description

The binding is held only during the satisfaction of the goal that produced the instantiation/binding (lines 1–2). It is lost after the goal is satisfied (lines 4–5). The following are the mathematical Horn clauses in Section 14.5.3 represented in Prolog syntax for Horn clauses:

A set of six code lines in Prolog with Horn clauses.
Description

The factorial predicate binds its second parameter F to the factorial of the integer represented by its first parameter N:

A set of six code lines in Prolog with the factorial predicate.
Description

14.7.7 Negation as Failure in Prolog

The built-in +/1 (not) predicate in Prolog is not a logical not operator (i.e., ), so we must exercise care when using it. The goal +(G) succeeds if goal G cannot be proved, not if goal G is false. Thus, + is referred to as the not provable operator. Thus, the use of +/1 can produce counter-intuitive results:

A set of 14 code lines in Prolog that produces counter-intuitive results.
Description

Assume only the fact mother (mary) exists in the database. The predicate +(mother (M)) is asserting that “there are no mothers.” The response to the query on line 8 (i.e., false) is indicating that “there is a mother,” and not indicating that “there are no mothers.” In attempting to satisfy the goal on line 10, Prolog starts with the innermost term and succeeds with M = mary. It then proceeds outward to the next term. Once a term becomes false, the instantiation is released. Thus, on line 11, we do not see a substitution for X, which proves the goal on line 10, but we are only given true. Consider the following goals:

A set of 14 code lines in Prolog consisting of goals.
Description

Again, false is returned on line 2 without presenting a binding for M, which was released. Notice that the goals on lines 4 and 7 are the same—only the order of the subgoals is transposed. While the validity of the goal in logic is not dependent on the order of the subgoals, the order in which those subgoals are pursued is significant in Prolog. On line 5, we see that Prolog instantiated M to mary to prove the goal on line 4. However, the proof of the goal on line 7 fails at the first subgoal without binding M to mary.

14.7.8 Graphs

We can model graphs in Prolog using a list whose first element is a list of vertices and whose second element is a list of directed edges, where each edge is a list of two elements—the source and target of the edge. Using this list representation of a graph, a sample graph is [[a,b,c,d], [[a,b], [b,c], [c,d], [d,b]]]. Using the append/2 and member/2 predicates (and others not defined here, such as noduplicateedges/1 and makeset/2—see Programming Exercises 14.7.15 and 14.7.16, respectively), we can define the following graph predicates:

A set of seven code lines in Prolog with the graph predicate.
Description

The graph predicate (lines 1–3) tests whether a given list represents a valid graph by checking if there are no duplicate edges (line 2) and confirming that the defined edges do not use vertices that are not included in the vertex set (line 3). The flatten/2 and subset/2 predicates (line 3) are built into SWI-Prolog. The vertex predicate (line 5) accepts a graph and a vertex; it returns true if the graph is valid and the vertex is a member of that graph’s vertex set, and false otherwise. Similarly, the edge predicate (line 7) takes a graph and an edge; it returns true if the graph is valid and the edge is a member of that graph’s edge set, and false otherwise. The following are example goals:

A set of 13 code lines in Prolog with the graph predicate giving true and false results.
Description

These predicates serve as building blocks from which we can construct more graph predicates. For instance, we can check if one graph is a subgraph of another one:

A set of five code lines in Prolog for checking if one graph is a subgraph of another one.
Description

The following are subgraph goals :

A set of four code lines in Prolog consisting of subgraph goals.
Description

We can also check whether a graph has a cycle, or a cycle containing a given vertex. A cycle is a chain where the start vertex and the end vertex are the same vertex. A chain is a path of directed edges through a graph from a source vertex to a target vertex. Using a Prolog list representation, a chain is a list of vertices such that there is an edge between each pair of adjacent vertices in the list. Thus, in that representation of a chain, a cycle is a chain such that there is an edge from the final vertex in the list to the first vertex in the list. Consider the following predicate to test a graph for the presence of cycles:

A set of nine code lines in Prolog for testing a graph for the presence of cycles.
Description

Note that the cycle/2 predicate uses a chain/4 predicate (not defined here; see Programming Exercise 14.7.19) that checks for the presence of a path from a start vertex to an end vertex in a graph.

A set of six code lines in Prolog for testing the presence of a path in a graph.
Description

An independent set is a graph with no edges, or a set of vertices with no edges between them. A complete graph is a graph in which each vertex is adjacent to every other vertex. These two classes of graphs are complements of each other. To identify an independent set, we must check if the edge set is empty. In contrast, a complete graph has no self-edges (i.e., an edge from and to the same vertex), but all other possible edges. A complete directed graph with n vertices has exactly n × (n – 1) edges. Thus, we can check if a graph is complete by verifying that it is a valid graph, that it has no self-edges, and that the number of edges is described by the prior arithmetic expression. The following are independent and complete predicates for these types of graphs—proper is a helper predicate:

A set of 10 code lines in Prolog with independent and complete predicates.
Description

The list length/2 predicate (line 32) is built into SWI-Prolog. The following are goals involving independent and complete:

A set of 10 code lines in Prolog with goals involving independent and complete.
Description

14.7.9 Analogs Between Prolog and an RDBMS

Interaction with the Prolog interpreter is strikingly similar to interacting with a relational database management system (RDBMS) using SQL. Pursuing goals in Prolog is the analog of running queries against a database. Consider the following database of Prolog facts:

A set of nine code lines in Prolog listing a database of facts.
Description
Continuation of the code in Prolog listing a database of facts consisting of three lines.
Description

Each of the five predicates in this Prolog program (each containing multiple facts) is the analog of a table (or relation) in a database system. The following is a mapping from some common types of queries in SQL to their equivalent goals in Prolog.

Union

A set of 27 code lines in Prolog that lists titles of different books, their authors, and year published for union.
Description

While a comma (,) is the conjunction or the and operator in Prolog, a semicolon (;) is the disjunction or the or operator in Prolog.

Intersection

A set of nine code lines in Prolog that lists titles of different books, their authors, and year published for intersection.
Description

Difference

A set of eight code lines in Prolog that lists titles of different books, their authors, and year published for difference.
Description

Projection

A set of nine code lines in Prolog that lists titles of different books for projection.
Description

Selection

A set of eight code lines in Prolog that lists titles of different books and the year published for selection.
Description

Projection Following Selection

A set of eight code lines in Prolog that lists titles of different books by an author for projection following selection.
Description

Natural Join

A set of four code lines in Prolog that lists titles of different books, their authors, year published, and the birthplace and date of birth of the authors for natural join.
Description
Continuation of the code in Prolog that lists titles of different books, their authors, year published, and the birthplace and date of birth of the authors for natural join, consisting of 26 lines.
Description

Theta-Join

A set of 21 code lines in Prolog that lists titles of different books, their authors, year published, and the birthplace and date of birth of the authors for theta join.
Description

Adding the preceding queries in the form of rules creates what are called views in database terminology, where the head of the headed Horn clause is the name of the view:

A set of three code lines in Prolog for adding the preceding queries in the form of rules.
Description
Continuation of the code in Prolog for adding the preceding queries in the form of rules, consisting of 22 lines.
Description

Table 14.15 presents analogs between Relational Database Management Systems and Prolog. Datalog is a non-Turing-complete subset of Prolog for use with deductive databases or rule-based databases.

Table 14.15 Analogs Between a Relational Database Management System (RDBMS) and Prolog

A table of the comparison between R D B M S and Prolog.
Description

Conceptual Exercises for Sections 14.614.7

Exercise 14.7.1 Prolog is a declarative programming language. What does this mean?

Exercise 14.7.2 Give an example of a language supporting declarative/logic programming other than Prolog.

Exercise 14.7.3 Explain why the +/1 Prolog predicate is not a true logical NOT operator. Provide an example to support your explanation.

Exercise 14.7.4 Does Prolog use short-circuit evaluation? Provide a Prolog goal (and the response the interpreter provides in evaluating it) to unambiguously support your answer. Note that the result of the goal ?– 3 = 4, 3 = 3. does not prove or disprove the use of short-circuit evaluation in Prolog.

Exercise 14.7.5 Since the depth-first search strategy is problematic for reasons demonstrated in Section 14.7.1, why does Prolog use depth-first search? Why is breadth-first search not used instead?

Exercise 14.7.6 In Section 14.7.1, we saw that left-recursion on the left-hand side of a rule causes a stack overflow. Why is this not the case in the reverse predicate in Section 14.7.4?

Exercise 14.7.7 Consider the following Prolog predicate a :- b, c,d., where b, c, and d can represent any subgoals. Prolog will try to satisfy subgoals b, c, and d, in that order. However, might Prolog satisfy subgoal c before it satisfies subgoal b? Explain.

Exercise 14.7.8 Reconsider the factorial predicate presented in Section 14.7.6. Explain why the goal factorial(N,120) results in an error.

Exercise 14.7.9 Consider the following Prolog goal and its result:

A set of two code lines in Prolog.
Description

Explain why the result of the following Prolog goal does not bind X to 1:

A set of two code lines in Prolog.
Description

Exercise 14.7.10 Which approach to resolution is more complex: backward chaining or forward chaining? Explain with reasons.

Programming Exercises for Sections 14.614.7

Exercise 14.7.11 Reconsider the append1/3 predicate in Section 14.7.4:

A set of three code lines in Prolog with the append 1 predicate.
Description

This predicate has a bug—it produces duplicate solutions (lines 4–5, 8–9, 12–13, 14–15, and 16–17):

A set of 20 code lines in Prolog that produces duplicate solutions.
Description

This bug propagates when append1 is used as a primitive construct to define other (list) predicates. Modify the definition of append1 to eliminate this bug:

A set of 11 code lines in Prolog with append 1 predicate.
Description

Exercise 14.7.12 Define a Prolog predicate reverse(L, R) that succeeds when the list R represents the list L with its elements reversed, and fails otherwise. Your predicate must not produce duplicate results. Use no auxiliary predicates, except for append/3.

Exercise 14.7.13 Define a Prolog predicate sum that binds its second argument S to the sum of the integers from 1 up to and including the integer represented by its first parameter N.

Examples:

A set of eight code lines in Prolog with the sum predicate.
Description
Continuation of the code in Prolog with the sum predicate, consisting of six lines.
Description

Exercise 14.7.14 Consider the following logical description for the Euclidean algorithm to compute the greatest common divisor (gcd) of two positive integers u and v:

The gcd of u and 0 is u.

The gcd of u and v, if v is not 0, is the same as the gcd of v and the remainder of dividing v into u.

Define a Prolog predicate gcd (U, V, W) that succeeds if W is the greatest common divisor of U and V, and fails otherwise.

Exercise 14.7.15 Reconsider the list representation of an edge in a graph described in Section 14.7.8. Define a Prolog predicate noduplicateedges/1 that accepts a list of edges and that returns true if the list of edges is a set (i.e., has no duplicates) and false otherwise. Use no auxiliary predicates, except for not/1 and member/2.

Examples:

A set of four code lines in Prolog with the no duplicate edges predicate.
Description

Exercise 14.7.16 Define a Prolog predicate makeset/2 that accepts a list and removes any repeating elements—producing a set. The result is returned in the second list parameter. Use no auxiliary predicates, except for not/1 and member/2.

Examples:

A set of eight code lines in Prolog with the make set predicate.
Description

Exercise 14.7.17 Using only append, define a Prolog predicate adjacent that accepts only three arguments and that succeeds if its first two arguments are adjacent in its third list argument and fails otherwise.

Examples:

A set of 12 code lines in Prolog with the adjacent predicate.
Description

Exercise 14.7.18 Modify your solution to Programming Exercise 14.7.17 so that the list is circular.

Examples:

A set of six code lines in Prolog with the adjacent predicate.
Description

Exercise 14.7.19 Reconsider the description of a chain in a graph described in Section 14.7.8. Define a Prolog predicate chain/4 that returns true if the graph represented by its first parameter contains a chain (represented by its fourth parameter) from the source vertex and target vertex represented by its second and third parameters, respectively, and false otherwise.

Examples:

A set of eight code lines in Prolog with the chain predicate.
Description

Exercise 14.7.20 Define a Prolog predicate sort that accepts two arguments, sorts its first integer list argument, and returns the result in its second integer list argument.

Examples:

A set of four code lines in Prolog with the sort predicate.
Description
A set of five code lines in Prolog with the less than predicate.
Description

The Prolog less than predicate is <:

A set of four code lines in Prolog with the last predicate.
Description

Exercise 14.7.21 Define a Prolog predicate last that accepts only two arguments and that succeeds if its first argument is the last element of its second list argument and fails otherwise.

Examples:

A table with three columns: p, q, and p NAND q. The row entries are as follows. Row 1: 0, 0, 1. Row 2: 1, 0, 1. Row 3: 0, 1, 1. Row 4: 1, 1, 0.

Exercise 14.7.22 Define a Prolog nand/3 predicate. The following table models a nand gate:

A table with three columns: p, q, and p NAND q. The row entries are as follows. Row 1: 0, 0, 1. Row 2: 1, 0, 1. Row 3: 0, 1, 1. Row 4: 1, 1, 0.

Exercise 14.7.23 A multiplexer is a device that connects one of many inputs to a single output through one or more selector lines, which collectively model the numeric position of the selected input as a binary number. Define a Prolog predicate that acts as a 4-input 2-bit multiplexer.

Examples:

A set of four code lines with a multiplexer.
Description

Exercise 14.7.24 Define a Prolog predicate validdate(Month,Day,Year) that accepts only three arguments, which represent a month, day, and year, in that order. The predicate succeeds if these arguments represent a valid date in the Gregorian calendar, and fails otherwise. For example, date (oct, 15, 1996) is valid, but date (jun, 31, 1921) is not. You must account for both different numbers of days in different months and February in leap years. A leap year is a year that is divisible by 400, or divisible by 4 but not also by 100. Therefore, 2000, 2012, 2016, and 2020 were leap years, while 1800 and 1900 were not. Your solution must not use more than three user-defined predicates or exceed 20 lines of code.

Examples:

A set of 13 code lines with the valid date predicate.
Description
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.111.208