LPN: reorg, split notes from exocortex page.
The exocortex page was getting unwieldy, this makes more sense.
This commit is contained in:
		
							parent
							
								
									36ed6df77f
								
							
						
					
					
						commit
						6d4fb673ef
					
				| 
						 | 
				
			
			@ -0,0 +1,97 @@
 | 
			
		|||
## Some basic syntax
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
property(name).
 | 
			
		||||
proposition.
 | 
			
		||||
/* rules */
 | 
			
		||||
head :- tail.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
happy(yolanda).
 | 
			
		||||
listens2Music(mia).
 | 
			
		||||
listens2Music(yolanda):- happy(yolanda).
 | 
			
		||||
playsAirGuitar(mia):- listens2Music(mia).
 | 
			
		||||
playsAirGuitar(yolanda):- listens2Music(yolanda).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Rules
 | 
			
		||||
 | 
			
		||||
Conditional fact:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
/* source */
 | 
			
		||||
listensToMusic(X) :- happy(X).
 | 
			
		||||
playsAirGuitar(X) :- listensToMusic(X).
 | 
			
		||||
happy(a).
 | 
			
		||||
/* interactive */
 | 
			
		||||
playsAirGuitar(a). /* true */
 | 
			
		||||
playsAirGuitar(b). /* false */
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## KB5
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
loves(vincent,mia).
 | 
			
		||||
loves(marsellus,mia).
 | 
			
		||||
loves(pumpkin,honey_bunny).
 | 
			
		||||
loves(honey_bunny,pumpkin).
 | 
			
		||||
jealous(X,Y):- loves(X,Z), loves(Y,Z).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note that when you enter queries, sometimes it waits for you to enter something
 | 
			
		||||
(so far seems like a semi-colon finishes a query). For example:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
2 ?- jealous(vincent, W).
 | 
			
		||||
W = vincent
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Output freezes there, waiting on input. Enter the semicolon:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
2 ?- jealous(vincent, W).
 | 
			
		||||
W = vincent ;
 | 
			
		||||
W = marsellus.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Replacing both atoms with variable:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
3 ?- jealous(A, B).
 | 
			
		||||
A = B, B = vincent ;
 | 
			
		||||
A = vincent,
 | 
			
		||||
B = marsellus ;
 | 
			
		||||
A = marsellus,
 | 
			
		||||
B = vincent ;
 | 
			
		||||
A = B, B = marsellus ;
 | 
			
		||||
A = B, B = pumpkin ;
 | 
			
		||||
A = B, B = honey_bunny.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This brings up something interesting: *jealous(A, A)* is always true:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
4 ?- jealous(A, A).
 | 
			
		||||
A = vincent ;
 | 
			
		||||
A = marsellus ;
 | 
			
		||||
A = pumpkin ;
 | 
			
		||||
A = honey_bunny.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Can we fix that in the definitions?
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
jealous(X,Y):- loves(X,Z), loves(Y,Z), X \= Y.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Now:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
9 ?- jealous(A, A).
 | 
			
		||||
false.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Re-reading a previous section, seems that ';' means "or".
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
## Unification
 | 
			
		||||
 | 
			
		||||
Two terms unify if they are
 | 
			
		||||
1. The same term
 | 
			
		||||
2. They contain variables that can be uniformly instantiated such that the
 | 
			
		||||
   resulting terms are equal.
 | 
			
		||||
 | 
			
		||||
Unification is foundational to Prolog.
 | 
			
		||||
 | 
			
		||||
`=/2` checks whether its two arguments unify:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
12 ?- =(a, a).
 | 
			
		||||
true.
 | 
			
		||||
13 ?- =(a, b).
 | 
			
		||||
false.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
*NB* variable assignment with `=`:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
24 ?- vincent = X.
 | 
			
		||||
X = vincent.
 | 
			
		||||
25 ?- jealous(Y, X).
 | 
			
		||||
Y = vincent,
 | 
			
		||||
X = marsellus ;
 | 
			
		||||
Y = marsellus,
 | 
			
		||||
X = vincent ;
 | 
			
		||||
false.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Lines
 | 
			
		||||
```
 | 
			
		||||
/* lines.pl */
 | 
			
		||||
vertical(line(point(X,Y),point(X,Z))).
 | 
			
		||||
horizontal(line(point(X,Y),point(Z,Y))).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Check this out:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
39 ?- vertical(line(point(1, 7), P)).
 | 
			
		||||
P = point(1, _402).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The answer is structured: `_402` is a placeholder variable that means "any old
 | 
			
		||||
value of Y will do." This answer was derived solely through unification, and
 | 
			
		||||
didn't require logic (e.g. modus ponens) or any sort of mathematical
 | 
			
		||||
relationships. "Moreover, when a program is written that makes heavy use of
 | 
			
		||||
unification, it is likely to be extremely efficient."
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
%% facts
 | 
			
		||||
child(anne,bridget).
 | 
			
		||||
child(bridget,caroline).
 | 
			
		||||
child(caroline,donna).
 | 
			
		||||
child(donna,emily).
 | 
			
		||||
 | 
			
		||||
%% rules
 | 
			
		||||
descend(X,Y) :- child(X,Y).
 | 
			
		||||
 | 
			
		||||
descend(X,Y) :- child(X,Z),
 | 
			
		||||
  descend(Z,Y).
 | 
			
		||||
 | 
			
		||||
descend1(X,Y) :- child(X,Y).
 | 
			
		||||
descend1(X,Y) :- child(X,Z),
 | 
			
		||||
  descend1(Z,Y).
 | 
			
		||||
 | 
			
		||||
descend2(X,Y) :- child(X,Y).
 | 
			
		||||
descend2(X,Y) :- descend2(Z,Y),
 | 
			
		||||
  child(X,Z).
 | 
			
		||||
 | 
			
		||||
%% WARNING: non-terminating.
 | 
			
		||||
descend3(X,Y)  :-  child(X,Y).
 | 
			
		||||
descend3(X,Y)  :-  descend3(X,Z),
 | 
			
		||||
                   descend3(Z,Y).
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
%% infinite recursion.
 | 
			
		||||
p :- p.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
directlyIn(natasha, irina).
 | 
			
		||||
directlyIn(olga, natasha).
 | 
			
		||||
directlyIn(katarina, olga).
 | 
			
		||||
 | 
			
		||||
in(X, Y) :- directlyIn(X, Y).
 | 
			
		||||
in(X, Y) :- directlyIn(X, Z),
 | 
			
		||||
            in(Z, Y).
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,162 @@
 | 
			
		|||
## Recursion
 | 
			
		||||
 | 
			
		||||
Recursive definitions require that the recursive function isn't the first
 | 
			
		||||
clause, ex:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
is_digesting(X,Y) :- just_ate(X,Y).
 | 
			
		||||
is_digesting(X,Y) :-
 | 
			
		||||
just_ate(X,Z),
 | 
			
		||||
is_digesting(Z,Y).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Recursive definition require a base ("escape") clause in addition to the
 | 
			
		||||
recursive clause.
 | 
			
		||||
 | 
			
		||||
### Rule ordering, goal ordering, and termination
 | 
			
		||||
 | 
			
		||||
Underlying vision for Prolog (and logic programming in general): the programmer
 | 
			
		||||
should be able to describe problems, and the computer derives the solution. The
 | 
			
		||||
programmer builds a knowledge base, then asks question of the computer.
 | 
			
		||||
 | 
			
		||||
Prolog's search order:
 | 
			
		||||
 | 
			
		||||
1. KB from top to bottom
 | 
			
		||||
2. Clauses from left to right
 | 
			
		||||
3. Backtracks on bad choices
 | 
			
		||||
 | 
			
		||||
This is somewhat of a procedural approach to declarative programming which may
 | 
			
		||||
affect the answer. Compare `descend1` with `descend2`:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
child(anne,bridget).
 | 
			
		||||
child(bridget,caroline).
 | 
			
		||||
child(caroline,donna).
 | 
			
		||||
child(donna,emily).
 | 
			
		||||
 | 
			
		||||
descend1(X,Y) :- child(X,Y).
 | 
			
		||||
descend1(X,Y) :- child(X,Z),
 | 
			
		||||
                 descend1(Z,Y).
 | 
			
		||||
 | 
			
		||||
descend2(X,Y) :- descend2(Z,Y),
 | 
			
		||||
                 child(X,Z).
 | 
			
		||||
 | 
			
		||||
descend2(X,Y) :- child(X,Y).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Supposedly these give different answers, but `swipl` exploded on the latter...
 | 
			
		||||
and continuing reading, that's the point --- a warning to avoid left-recursive
 | 
			
		||||
rules.
 | 
			
		||||
 | 
			
		||||
The takeaway is that you can get the overall idea of how to write the program
 | 
			
		||||
by approaching the problem declaratively. Sensible goal orderings ensure
 | 
			
		||||
program / query termination: place the recursive definition last.
 | 
			
		||||
 | 
			
		||||
### Exercises
 | 
			
		||||
 | 
			
		||||
#### Exercise 3.1
 | 
			
		||||
 | 
			
		||||
In the text, we discussed the predicate
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
descend(X,Y)  :-  child(X,Y).
 | 
			
		||||
descend(X,Y)  :-  child(X,Z),
 | 
			
		||||
                  descend(Z,Y).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Suppose we reformulated this predicate as follows:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
descend(X,Y)  :-  child(X,Y).
 | 
			
		||||
descend(X,Y)  :-  descend(X,Z),
 | 
			
		||||
                  descend(Z,Y).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Would this be problematic?
 | 
			
		||||
 | 
			
		||||
**A**: yes: there's no termination clause. See `descend3` in `descend.pl`.
 | 
			
		||||
 | 
			
		||||
#### Exercise 3.2
 | 
			
		||||
 | 
			
		||||
Do you know these wooden Russian dolls (Matryoshka dolls) where the smaller
 | 
			
		||||
ones are contained in bigger ones?
 | 
			
		||||
 | 
			
		||||
Ex katarina(olga(natasha(irina))).
 | 
			
		||||
 | 
			
		||||
First, write a knowledge base using the predicate `directlyIn/2` which encodes
 | 
			
		||||
which doll is directly contained in which other doll. Then, define a recursive
 | 
			
		||||
predicate `in/2`, that tells us which doll is (directly or indirectly)
 | 
			
		||||
contained in which other dolls. For example, the query `in(katarina,natasha)`
 | 
			
		||||
should evaluate to true, while `in(olga, katarina)` should fail.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
directlyIn(natasha, irina).
 | 
			
		||||
directlyIn(olga, natasha).
 | 
			
		||||
directlyIn(katarina, olga).
 | 
			
		||||
 | 
			
		||||
in(X, Y) :- directlyIn(X, Y).
 | 
			
		||||
in(X, Y) :- directlyIn(X, Z),
 | 
			
		||||
            in(Z, Y).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Exercise 3.3
 | 
			
		||||
 | 
			
		||||
We have the following knowledge base:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
directTrain(saarbruecken,dudweiler).
 | 
			
		||||
directTrain(forbach,saarbruecken).
 | 
			
		||||
directTrain(freyming,forbach).
 | 
			
		||||
directTrain(stAvold,freyming).
 | 
			
		||||
directTrain(fahlquemont,stAvold).
 | 
			
		||||
directTrain(metz,fahlquemont).
 | 
			
		||||
directTrain(nancy,metz).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
That is, this knowledge base holds facts about towns it is possible to travel
 | 
			
		||||
between by taking a direct train. But of course, we can travel further by
 | 
			
		||||
chaining together direct train journeys. Write a recursive predicate
 | 
			
		||||
`travelFromTo/2` that tells us when we can travel by train between two towns.
 | 
			
		||||
For example, when given the query `travelFromTo(nancy,saarbruecken)` it should
 | 
			
		||||
reply yes.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
travelFromTo(X, Y) :- directTrain(X, Y).
 | 
			
		||||
travelFromTo(X, Y) :- directTrain(X, Z),
 | 
			
		||||
                      travelFromTo(Z, Y).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Exercise 3.4
 | 
			
		||||
 | 
			
		||||
Define a predicate `greater_than/2` that takes two numerals in the notation
 | 
			
		||||
that we introduced in the text (that is, `0`, `succ(0)`, `succ(succ(0))`, and
 | 
			
		||||
so on) as arguments and decides whether the first one is greater than the
 | 
			
		||||
second one. For example:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
?-  greater_than(succ(succ(succ(0))),succ(0)).
 | 
			
		||||
yes
 | 
			
		||||
?-  greater_than(succ(succ(0)),succ(succ(succ(0)))).
 | 
			
		||||
no
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Exercise 3.5
 | 
			
		||||
 | 
			
		||||
Binary trees are trees where all internal nodes have exactly two children. The
 | 
			
		||||
smallest binary trees consist of only one leaf node. We will represent leaf
 | 
			
		||||
nodes as `leaf(Label)`. For instance, `leaf(3)` and `leaf(7)` are leaf nodes,
 | 
			
		||||
and therefore small binary trees. Given two binary trees B1 and B2 we can
 | 
			
		||||
combine them into one binary tree using the functor `tree/2` as follows:
 | 
			
		||||
`tree(B1,B2)`. So, from the leaves `leaf(1)` and `leaf(2)` we can build the
 | 
			
		||||
binary tree `tree(leaf(1),leaf(2))` . And from the binary trees
 | 
			
		||||
`tree(leaf(1),leaf(2))` and `leaf(4)` we can build the binary tree
 | 
			
		||||
`tree(tree(leaf(1), leaf(2)),leaf(4))`.
 | 
			
		||||
 | 
			
		||||
Now, define a predicate `swap/2`, which produces the mirror image of the binary
 | 
			
		||||
tree that is its first argument. For example:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
?-  swap(tree(tree(leaf(1),  leaf(2)),  leaf(4)),T).
 | 
			
		||||
T  =  tree(leaf(4),  tree(leaf(2),  leaf(1))).
 | 
			
		||||
yes
 | 
			
		||||
```
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
numeral(0).
 | 
			
		||||
numeral(succ(X)) :- numeral(X).
 | 
			
		||||
 | 
			
		||||
%% add/3: add(X, Y, Z) -> X + Y = Z
 | 
			
		||||
add(0, X, X).
 | 
			
		||||
add(succ(X), Y, succ(Z)) :-
 | 
			
		||||
  add(X, Y, Z).
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
%% Given facts.
 | 
			
		||||
directTrain(saarbruecken,dudweiler).
 | 
			
		||||
directTrain(forbach,saarbruecken).
 | 
			
		||||
directTrain(freyming,forbach).
 | 
			
		||||
directTrain(stAvold,freyming).
 | 
			
		||||
directTrain(fahlquemont,stAvold).
 | 
			
		||||
directTrain(metz,fahlquemont).
 | 
			
		||||
directTrain(nancy,metz).
 | 
			
		||||
 | 
			
		||||
%% Rules.
 | 
			
		||||
travelFromTo(X, Y) :- directTrain(X, Y).
 | 
			
		||||
travelFromTo(X, Y) :- directTrain(X, Z),
 | 
			
		||||
                      travelFromTo(Z, Y).
 | 
			
		||||
		Loading…
	
		Reference in New Issue