- PA 7 is out, due Fri 6/8

- Bear with us, but let us know of anomalies

Tuesday

**6/12/2012**from**7-10pm**CENTER 105

Stay tuned for

**review session**

**Program**=**Algorithm**+**Data Structures**

**Execute**

**Program**=**Facts**+**Rules**

**Query**

- 1970s: Logic + Automated Theorem Proving

- Developed for
**Artificial Intelligence**

*Carnitas is Mexican*

*Mexican food is delicious*

*What is a delicious food ?*

*Carnitas!*

- Specify
**what**you want

- Specify
**desired properties**of result

- Not
**how**to obtain result

Ideal for Searching Large Space of Results

- It is often
**hard**to specify**search**algorithm

- But
**easy**to specify the characteristics of the solution.

- Airports, Flights, Times, Durations, Costs

**If**travel from`A`

to`B`

with price (`P1`

)**AND**`B`

to`C`

with price (`P2`

)...

**Then**

- travel from
`A`

to`C`

with price (`P1 + P2`

) ...

- What is cheapest flight from SAN to JFK with duration < 6 Hrs ?

**El Cuervo**makes CA Burrito (profit =`$2`

), Fish Taco (profit =`$1`

)

- Burrito Capacity <
`200`

- Taco Capacity <
`500`

- Total Capacity <
`400`

```
max 2.x + 1.y /* profit */
s.t. x < 200 /* burrito capacity */
y < 400 /* taco capacity */
x+y < 300 /* total capacity */
0 < x, y /* must produce! */
```

Used heavily in many domains (together with statistical methods)

- Scheduling
- Travel, Sports, ...

- Rule-based Anomaly detection
- Credit card fraud!

- SQL (and similar DB Query Languages)
- Find all pairs of stocks, with same price on same day,
- More than 50 times last year

- Many of these are inspired-by / subsets of Prolog ...

- Terms
- Facts
- Queries (Implementation: Unification)
- Rules
- Programs (Implementation: Backtracking Search)

- Numeric Computation
- Data Structures
- Puzzle Solving

Prolog Program

**Facts****Rules**

... but facts and rules **about what** ?

- Terms

"Tree-like" values, similar to Ocaml ADTs

**Constants**

**Atoms**

**Variables**

**Compound Terms**

**Constants** the simplest term, representing primitive values

- Basic types like integers, reals

- Examples:
`1`

,`92`

,`4.4`

**Atom:** any identifier starting with **lower**-case

`x`

,`alice`

,`taco`

,`giraffe`

,`appleSauce`

**Atom:** any identifier starting with **lower**-case

`x`

,`alice`

,`taco`

,`giraffe`

,`appleSauce`

- Elements of a single mega
**enum**type

- Similar to tags used in ML types (except ML tags are uppercase)

`type atoms = x | alice | taco | giraffe | appleSauce | ...`

**Atom:** any identifier starting with **lower**-case

`x`

,`alice`

,`taco`

,`giraffe`

,`appleSauce`

- Prolog knows
**NOTHING**about the tags, they are just**names**

- Each tag is
**equal to**itself (more later...)`alice = alice`

`taco = taco`

- Each tag is
**disequal to**every**other**tag`alice = taco`

**never**holds in Prolog

**Variables:** any identifier starting with **upper**-case

`X`

,`Y`

,`Z`

,`Head`

,`Tail`

,`Taco`

,`Burrito`

,`Alice`

,`Bob`

`_`

is the**wildcard**variable, similar to`ML`

- Even though
`x = a`

makes**no sense**to Prolog ...

- ...
`X = a`

does have a meaning but**not**what you might think!

**Compound** terms are of form `atom(term1, term2, term3, ...)`

Where each `term`

is **one-of**

- constant
- atom
- variable
- compound term

**Compound** terms are of form `atom(term1, term2, term3, ...)`

Where each `term`

is **one-of**

- constant
- atom
- variable
- compound term

```
x(y, z) % y, z are atoms
parent(alice, bob) % alice, bob are atoms
parent(alice, Child) % alice is an atom, Child is a variable
```

- Terms are NOT Function Calls!

- More like
**trees**

**Compound** terms are of form `atom(term1, term2, term3, ...)`

Each `term`

is **one-of**

- constant
- atom
- variable
- compound term

```
type term = Constant of int
| Atom of string
| Variable of string
| Compound of string * term list
```

```
type term = Constant of int
| Atom of string
| Variable of string
| Compound of string * term list
```

(Hint: **atom** = lowercase, **variable** = uppercase)

Which **Ocaml** value of type `term`

represents **Prolog** term `parent(alice, bob)`

?

**A.** `parent ("alice", "bob")`

**B.** `parent (Atom "alice", Atom "bob")`

**C.** `[Atom "parent"; Atom "alice"; Atom "bob"]`

**D.** `Compound ("parent", [Atom "alice"; Atom "bob"])`

**E.** `Compound (Atom "parent", [Atom "alice"; Atom "bob"])`

Prolog term `parent(alice, Charlie)`

is represented by:

`Compound ("parent", [Atom "alice"; Var "Charlie"])`

```
type term = Constant of int
| Atom of string
| Variable of string
| Compound of string * term list
```

(Hint: **atom** = lowercase, **variable** = uppercase)

What Ocaml value of type `term`

represents Prolog term `factorial(5)`

?

**A.** `factorial(5)`

**B.** `factorial(Atom 5)`

**C.** `120`

**D.** `Constant 120`

**E.** `Compound ("factorial", [Constant 5])`

Prolog term `factorial(5)`

is simply the tree

- The term is just a box containing
`5`

labeled`factorial`

Prolog term `factorial(5)`

is simply the tree

- The term is just a box containing
`5`

labeled`factorial`

`factorial`

just a**label**called a**function symbol**

- Prolog has
**no idea**about**implementation**of function ...

- Terms
**Facts**- Queries (Implementation: Unification)
- Rules
- Programs (Implementation: Backtracking Search)

- Numeric Computation
- Data Structures
- Puzzle Solving

The following facts specify a list of **parent-child** relationships

```
parent(kim, holly).
parent(margaret, kim).
parent(herbert, margaret).
parent(john, kim).
parent(felix, john).
parent(albert, felix).
```

**Note**`kim`

,`holly`

,`margaret`

etc. are all**atoms**

- Facts are just terms (typically without variables.)

- Specified by term followed by
`.`

The following facts specify a list of **parent-child** relationships

```
parent(kim, holly).
parent(margaret, kim).
parent(herbert, margaret).
parent(john, kim).
parent(felix, john).
parent(albert, felix).
```

- You can make up and add new facts to the collection

- We will be able to ask Prolog
**queries**over these facts

The following facts specify a list of **parent-child** relationships

```
parent(kim, holly).
parent(margaret, kim).
parent(herbert, margaret).
parent(john, kim).
parent(felix, john).
parent(albert, felix).
```

- Represent functions that evaluate to a boolean

- e.g.
`parent`

is a predicate of**arity**2 (that takes 2 arguments)

The following facts specify a list of **parent-child** relationships

```
parent(kim, holly).
parent(margaret, kim).
parent(herbert, margaret).
parent(john, kim).
parent(felix, john).
parent(albert, felix).
```

`parent`

is a predicate of**arity**2 (that takes two arguments)

- Programmer
**mentally**notes that:`parent(kim, holly)`

**means**`kim`

is a "parent-of"`holly`

`parent(margaret, kim)`

**means**`margaret`

is a "parent-of"`kim`

- etc.

- Terms
- Facts
**Queries**(Implementation: Unification)- Rules
- Programs (Implementation: Backtracking Search)

- Numeric Computation
- Data Structures
- Puzzle Solving

Standard interface is a REPL shell

```
$ rlwrap swipl
130f@ieng6-202]:~:501$ swipl
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 5.10.5)
Copyright (c) 1990-2011 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?-
```

Suppose we have a collection of facts saved in lec-prolog.pl

You can **load** the facts in ...

```
?- consult('lec-prolog.pl').
% foo.pl compiled 0.00 sec, 10,640 bytes
true.
```

... or you can **add** them one-at-a-time

`?- assert(parent(margaret, kim)).`

Once facts are loaded, you **query** Prolog as follows:

**Plg:**Prompts you to type a query

**You:**Type a query

**Plg:**Tries to*prove*your query

**Plg:**Prints out the result (or`failure`

)

- Repeat (go to 1)

The simplest possible query ...

`?- parent(margaret, john). `

... a **fact** but typed at the prompt.

The simplest possible query ...

`?- parent(margaret, john). `

... a **fact** but typed at the prompt.

O Prolog, is this fact

inyour Database ... or can it beinferredfrom your database?

The simplest possible query ...

`?- parent(margaret, john). `

... a **fact** but typed at the prompt.

O Prolog, is this fact

inyour database ... or can it beinferredfrom your database?

```
?- parent(margaret, john).
false.
```

- This is
**not**one of the facts we gave it, and, - We are yet to supply it with
**rules**for inferring**new facts**.

A slightly different query yields a different result.

A slightly different query yields a different result.

```
?- parent(margaret, kim).
true.
```

- As this was indeed one of the facts loaded in lec-prolog

This is where Prolog starts to depart radically from other paradigms...

`?- parent(margaret,X).`

O Prolog, for

which value(s)of`X`

is the factprovable?

This is where Prolog starts to depart radically from other paradigms...

`?- parent(margaret,X).`

O Prolog, for

which value(s)of`X`

is the factprovable?

`X = kim.`

As when it **plugs-in** `kim`

for `X`

, it can infer `parent(margaret, kim)`

.

Suppose we *flip* the query.

`?- parent(X, kim).`

O Prolog, for

which value(s)of`X`

is`parent(X, kim)`

provable?

Suppose we *flip* the query.

`?- parent(X, kim).`

O Prolog, who are the

parents-of`kim`

?

Suppose we *flip* the query.

`?- parent(X, kim).`

O Prolog, who are the

parents-of`kim`

?

```
?- parent(X, kim).
X = margaret ; % [press ';' if you want another solution]
X = john ; % [press ';' if you want another solution]
false. % [thats all folks, no more solutions ]
```

Returns **all solutions** for `X`

that make `parent(X, kim)`

provable.

We can write queries with *multiple* variables.

`?- parent(X, Y).`

O Prolog, for which pairs

`X`

,`Y`

is`parent(X, Y)`

provable?

We can write queries with *multiple* variables.

`?- parent(X, Y).`

O Prolog, for which pairs

`X`

,`Y`

is`parent(X, Y)`

provable?

```
?- parent(X, Y).
X = kim, Y = holly ;
X = margaret, Y = kim ;
X = herbert, Y = margaret;
X = john, Y = kim ;
X = felix, Y = john ;
X = albert, Y = felix ;
X = albert, Y = dana ;
X = felix, Y = maya .
```

Enumerates **all facts** in the `parent`

database.

Suppose we want to know if there are any strange circularities in the database:

Does there exist

anyperson who is theirown parent?

Which of the following encodes the above in Prolog?

**A.** `parent(kim, kim)`

**B.** `parent(x, x)`

**C.** `parent(X, X)`

**D.** `parent(X, Y)`

**E.** `parent(Y, X)`

In Java/C# or for that matter ML/Scala/... you would need

- Some
`parentOf`

or`childOf`

methods- to represent parent-child relationship

- Some looping or iteration
- to search through all pairs

- Instead, Prolog uses
**facts**and**queries**- to search
**forwards**and**backwards** - to enumerate all results
- in a single uniform
**declarative**manner!

- to search

- Terms
- Facts
- Queries (Implementation:
**Unification**) - Rules
- Programs (Implementation: Backtracking Search)

- Numeric Computation
- Data Structures
- Puzzle Solving

We can

substitutevalues for theirvariablesto make the termsidentical

In Prolog, when you write (e.g. in a query)

`?- term1 = term2.`

you are asking whether `term1`

**can be unified with** `term2`

.

```
?- kim = kim.
true.
```

Two **same atoms** are **trivially** unified.

```
?- kim = holly.
false.
```

Two **different atoms** can **never** be unified.

```
?- foo(kim) = foo(kim).
true.
```

As there are no variables, and the terms **are already** identical.

```
?- foo(kim) = foo(holly).
false.
```

As there are no variables, and the terms **can never be** identical.

`?- X = kim.`

**Q:**When is the term`X`

**identical to**the term`kim`

?

**A:**When we**substitute**`X`

with the value`kim`

!

`?- foo(X) = foo(kim).`

**Q:**When is the term`X`

**identical to**the term`kim`

?**A:**When we**substitute**`X`

with the value`kim`

!

```
?- foo(X) = foo(kim).
X = kim.
```

- Pretty simple...

How does Prolog respond to the following query?

`?- foo(X, dog) = foo(cat, Y).`

**A.** `false`

**B.** `X = cat, Y = cat.`

**C.** `X = dog, Y = dog.`

**D.** `X = dog, Y = cat.`

**E.** `X = cat, Y = dog.`

`?- p(X, dog, X) = p(cat, Y, Y).`

`?- p(X, dog, X) = p(cat, Y, Y).`

The **top** nodes of both trees have **same predicate** ... go inside.

`?- p(X, dog, X) = p(cat, Y, Y).`

To unify `X`

and `cat`

use **substitution** `X = cat`

`?- p(X, dog, X) = p(cat, Y, Y).`

Apply substitution `X = cat`

to both terms. Move on to next leaf...

`?- p(X, dog, X) = p(cat, Y, Y).`

To unify `dog`

and `Y`

use **substitution** `Y = dog`

...

`?- p(X, dog, X) = p(cat, Y, Y).`

... and apply substitution throughout **both** terms.

`?- p(X, dog, X) = p(cat, Y, Y).`

Uh oh, now last leaf has **different** atoms...

`?- p(X, dog, X) = p(cat, Y, Y).`

... impossible to unify `cat`

and `dog`

. **Unification fails.**

```
?- p(X, dog, X) = p(cat, Y, Y).
false.
```

How does Prolog respond to the following unification query?

`?- a(W, foo(W, Y), Y) = a(2, foo(X, 3), Z).`

**A.** `false.`

(No unification possible)

**B.** `W = 2, X = 2, Y = 2, Z = 2.`

**C.** `W = 2, X = 2, Y = 3, Z = 3.`

**D.** `W = 3, X = 3, Y = 2, Z = 2.`

**C.** `W = 2, X = 3, Y = 2, Z = 3.`

How does Prolog respond to the following unification query?

`?- a(W, foo(W, Y), Y) = a(2, foo(X, 3), Z).`

- Subst
`W = 2`

. Query is:`a(2, foo(2, Y), Y) = a(2, foo(X, 3), Z).`

- Subst
`X = 2`

. Query is:`a(2, foo(2, Y), Y) = a(2, foo(2, 3), Z).`

- Subst
`Y = 3`

. Query is:`a(2, foo(2, 3), 3) = a(2, foo(2, 3), Z).`

- Subst
`Z = 3`

. Query is:`a(2, foo(2, 3), 3) = a(2, foo(2, 3), 3).`

**Done!**

How does Prolog respond to the following unification query?

```
?- a(W, foo(W, Y), Y) = a(2, foo(X, 3), Z).
W = 2,
X = 2,
Y = 3,
Z = 3.
```

How does Prolog respond to the following unification query?

`?- a(W, foo(W, Y), Y) = a(2, foo(X, 3), X).`

**A.** `false.`

(No unification possible)

**B.** `W = 2, X = 2, Y = 2, Z = 2.`

**C.** `W = 2, X = 2, Y = 3, Z = 3.`

**D.** `W = 3, X = 3, Y = 2, Z = 2.`

**C.** `W = 2, X = 3, Y = 2, Z = 3.`

How does Prolog respond to the following unification query?

`?- a(W, foo(W, Y), Y) = a(2, foo(X, 3), X).`

- Subst
`W = 2`

. Query is:`a(2, foo(2, Y), Y) = a(2, foo(X, 3), X).`

- Subst
`X = 2`

. Query is:`a(2, foo(2, Y), Y) = a(2, foo(2, 3), 2).`

- Subst
`Y = 3`

. Query is:`a(2, foo(2, 3), 3) = a(2, foo(2, 3), 2).`

`3 = 2`

cannot be unified,**Fail!**

When we ask

`?- parent(margaret, X). `

Prolog checks if the above term **can be unified** with any **known fact** (term).

- If
**unification succeeds**then it replies`true`

- And also the
**unifying substitutions**for`X`

- Which are the
**solutions**for the query!

- And also the

- If
**unification fails**then it replies`false`

When we ask

`?- parent(margaret, X). `

Prolog checks if the above term **can be unified** with any **known fact** (term).

- If
**unification succeeds**then it replies`true`

(and the**solutions**for`X`

) - If
**unification fails**then it replies`false`

```
?- parent(margaret, X).
X = kim.
```

When we ask

`?- parent(X, kim). `

When we ask

`?- parent(X, kim). `

Prolog checks if the above term **can be unified** with any **known fact** (term).

- If
**unification succeeds**then it replies`true`

(and the**solutions**for`X`

) - If
**unification fails**then it replies`false`

When we ask

`?- parent(X, kim). `

Prolog checks if the above term **can be unified** with any **known fact** (term).

- If
**unification succeeds**then it replies`true`

(and the**solutions**for`X`

) - If
**unification fails**then it replies`false`

```
?- parent(X, kim).
X = margaret ;
X = john .
```

Finally, when we ask

`?- parent(X, Y). `

Finally, when we ask

`?- parent(X, Y). `

Prolog checks if the above term **can be unified** with any **known fact** (term).

- If
**unification succeeds**it replies`true`

(and**solutions**for`X`

,`Y`

) - If
**unification fails**it replies`false`

Finally, when we ask

`?- parent(X, Y). `

Prolog checks if the above term **can be unified** with any **known fact** (term).

- If
**unification succeeds**it replies`true`

(and**solutions**for`X`

,`Y`

)

```
?- parent(X, Y).
X = kim, Y = holly ;
X = margaret, Y = kim ;
X = herbert, Y = margaret;
X = john, Y = kim ;
X = felix, Y = john ;
X = albert, Y = felix ;
X = albert, Y = dana ;
X = felix, Y = maya .
```

- Terms
- Facts
- Queries (Implementation: Unification)
**Rules**- Programs (Implementation: Backtracking Search)

- Numeric Computation
- Data Structures
- Puzzle Solving

Often useful to ask questions over **multiple** terms.

- For example, to determine if
`margaret`

is the**grandparent**of`holly`

Often useful to ask questions over **multiple** terms.

- For example, to determine if
`margaret`

is the**grandparent**of`holly`

`?- parent(margaret, X), parent(X, holly).`

- Is there a person
`X`

who is a child of`margaret`

**AND**a parent of`holly`

?

- Is there
`X`

s.t.`parent(margaret, X)`

**AND**`parent(X, holly)`

?

Often useful to ask questions over **multiple** terms.

- For example, to determine if
`margaret`

is the**grandparent**of`holly`

`?- parent(margaret, X), parent(X, holly).`

Is there a person

`X`

who is a child of`margaret`

**AND**a parent of`holly`

?Is there

`X`

s.t.`parent(margaret, X)`

**AND**`parent(X, holly)`

?

```
?- parent(margaret, X), parent(X, holly).
X = kim.
```

Often useful to ask questions over **multiple** terms.

- For example, to find the
**great-grandparents**of`kim`

Often useful to ask questions over **multiple** terms.

- For example, to find the
**great-grandparents**of`kim`

`?- parent(GGP, GP), parent(GP, P), parent(P, kim).`

**Note:** how we link the terms with a variable to capture relationships.

Often useful to ask questions over **multiple** terms.

- For example, to find the
**great-grandparents**of`kim`

`?- parent(GGP, GP), parent(GP, P), parent(P, kim).`

**Note:** how we link the terms with a variable to capture relationships.

Prolog finds appropriate **unifiers** and replies

```
?- parent(margaret, X), parent(X, holly).
GGP = john,
GP = felix,
P = albert.
```

i.e. `john`

is a **great-grandparent** following the above chain.

Which of these queries is true iff `margaret`

and `kim`

are (half-) **siblings**?

**A.** `parent(margaret, kim)`

**B.** `parent(margaret, X), parent(X, kim).`

**C.** `parent(kim, X), parent(X, margaret).`

**D.** `parent(margaret, X), parent(kim, X).`

**E.** `parent(X, margaret), parent(X, kim).`

- Conjunctions let us mine the database for complex relationships...

- ... but its cumbersome to
**repeatedly**write down long queries

- We need a way to
**compose**complex queries from simple queries...

`headQuery :- condQuery1, condQuery2, condQuery3,...`

`headQuery :- condQuery1, condQuery2, condQuery3,...`

**If**you can prove`condQuery1`

**AND**`condQuery2`

**AND**`...`

**Then**you can prove`headQuery`

`headQuery :- condQuery1, condQuery2, condQuery3,...`

To prove the

**goal**`headQuery`

...Prove

**subgoals**`condQuery1`

**AND**`condQuery2`

**AND**...

`grandparent`

predicateOur database includes a

`parent`

predicateLet us use it to

**define**a`grandparent`

predicate

`grandparent`

predicate`grandparent(GP, GC) :- parent(GP, P), parent(P, GC).`

`GP`

is a *grandparent* of `GC`

if `GP`

is a *parent* of `P`

**and** `P`

is a *parent* of `GC`

`grandparent`

predicate`grandparent(GP, GC) :- parent(GP, P), parent(P, GC).`

```
?- grandparent(X, kim). % who are the grandparents of kim
X = herbert ; % hit ; to see next
X = felix ; % hit ; to see next
false. % thats it!
```

`grandparent`

predicate`grandparent(GP, GC) :- parent(GP, P), parent(P, GC).`

```
?- grandparent(X, kim). % who are the grandparents of kim
X = herbert ; % hit ; to see next
X = felix ; % hit ; to see next
false. % thats it!
```

```
?- parent(herbert, P), parent(P, kim). %% Solution 1. X = herbert
P = margaret.
?- parent(felix, P), parent(P, kim). %% Solution 2. X = felix
P = john .
```

Which of the following is a valid `greatgrandparent`

predicate?

(Btw, **greatgrandparent** is the **parent** of a **grandparent**.)

```
% A
greatgrandparent(X, Y) :- parent(X, Y), grandparent(X, Y).
% B
greatgrandparent(X, Y) :- parent(X, Z), grandparent(Z, Y).
% C
greatgrandparent(X, Y) :- grandparent(X, Z), parent(Z, Y).
% D
greatgrandparent(X, Y) :- parent(X, Z), parent(Z, Y).
% E
greatgrandparent(X, Y) :- parent(X, Z), parent(Z, Z1), parent(Z1, Y).
```

`greatgrandparent`

predicate`greatgrandparent(GGP, GC) :- parent(GGP, GP), grandparent(GP, GC).`

`greatgrandparent`

predicate`greatgrandparent(GGP, GC) :- parent(GGP, GP), grandparent(GP, GC).`

```
?- greatgrandparent(X, holly).
X = herbert.
```

- Terms
- Facts
- Queries (Implementation: Unification)
- Rules
**Programs**(Implementation: Backtracking Search)

- Numeric Computation
- Data Structures
- Puzzle Solving

Facts and Rules are two kinds of **clauses**

**Fact:**Clause**without**any conditions

**Rules:**Clause**with**conditions

- Basic Facts / Predicates

- Rules for
**generating**new Facts / Predicates

Complex Programs need Complex Predicates with Multiple Rules

- Scope

- Multiple Rules: Disjunction

- Multiple Rules: Recursion

Complex Programs need Complex Predicates with Multiple Rules

**Scope**Multiple Rules: Disjunction

Multiple Rules: Recursion

A word about **scope**.

In the `grandparent`

rule, the variable `GP`

appears **twice**

`greatgrandparent(GGP, GC) :- parent(GGP, GP), grandparent(GP, GC).`

- In Prolog, the scope of a variable is the
**single**rule containing it.

- There is
**no connection**between variables**across**rules.

A word about **scope**.

In Prolog, the scope of a variable is the

**single**rule containing it.There is

**no connection**between variables**across**rules.

```
foo(P) :- bar(P). % There is no connection between P
stuff(P) :- thing(P). % across the two rules
```

Complex Programs need Complex Predicates with Multiple Rules

Scope

**Multiple Rules: Disjunction**Multiple Rules: Recursion

Lets write a predicate `has_family`

which is true for persons who

**either**have a parent

**or**have a child

Lets write a predicate `has_family`

which is true for persons who

**either**have a parent**or**have a child

```
has_family(X) :- parent(X, _). % if X is the parent of some _
has_family(X) :- parent(_, X). % if X is the child of some _
```

`_`

is a *wildcard* or *dont-care* variable (as in ML, Scala)

**If**we can prove`parent(X, _)`

**Then**we can prove`has_family(X)`

**If**we can prove`parent(_, X)`

**Then**we can prove`has_family(X)`

Lets write a predicate `has_family`

which is true for persons who

**either**have a parent**or**have a child

```
has_family(X) :- parent(X, _). % if X is the parent of some _
has_family(X) :- parent(_, X). % if X is the child of some _
```

```
?- has_family(holly).
true. % Second rule fires for holly
?- has_family(mugatu).
false. % Neither rule fires for mugatu
```

Lets write a predicate `has_family`

which is true for persons who

**either**have a parent**or**have a child

```
has_family(X) :- parent(X, _). % if X is the parent of some _
has_family(X) :- parent(_, X). % if X is the child of some _
```

Can be abbreviated to

`has_family(X) :- parent(X, _) ; parent(_, X).`

Semicolon `;`

indicates disjunction.

Complex Programs need Complex Predicates with Multiple Rules

Scope

Multiple Rules: Disjunction

**Multiple Rules: Recursion**

Lets write a predicate `ancestor(Anc, Child)`

which is true if

`parent(Anc, Child)`

...**or**

`parent(Anc, P)`

and`parent(P, Child)`

...**or**

`parent(Anc, GP)`

and`parent(GP, P)`

and`parent(P, Child)`

...**or**

- ... if
**some**chain of parent-links holds between`Anc`

and`Child`

.

Lets write a predicate `ancestor(Anc, Child)`

which is true if

... if **some** chain of parent-links holds between `Anc`

and `Child`

.

- If
`Anc`

is the parent of`Child`

`ancestor(Anc, Child) :- parent(Anc, Child).`

- If
`P`

is the parent of`Child`

and`Anc`

is an**ancestor**of`P`

`ancestor(Anc, Child) :- parent(P, Child), ancestor(Anc, P).`

Lets write a predicate `ancestor(Anc, Child)`

which is true if

... if **some** chain of parent-links holds between `Anc`

and `Child`

.

```
ancestor(Anc, Child) :- parent(Anc, Child).
ancestor(Anc, Child) :- parent(P, Child), ancestor(Anc, P).
```

Lets write a predicate `ancestor(Anc, Child)`

which is true if

... if **some** chain of parent-links holds between `Anc`

and `Child`

.

```
ancestor(Anc, Child) :- parent(Anc, Child).
ancestor(Anc, Child) :- parent(P, Child), ancestor(Anc, P).
```

Lets take it out for a spin!

First, lets find **descendants** (forwards)

```
?- ancestor(kim, X).
X = holly.
```

Lets write a predicate `ancestor(Anc, Child)`

which is true if

... if **some** chain of parent-links holds between `Anc`

and `Child`

.

```
ancestor(Anc, Child) :- parent(Anc, Child).
ancestor(Anc, Child) :- parent(P, Child), ancestor(Anc, P).
```

Lets take it out for a spin!

Next, lets find **ancestors** (backwards)

```
?- ancestor(X,kim).
X = margaret ;
X = john ;
X = herbert ;
X = felix ;
X = albert .
```

`kim`

has a long ancestry!