LPN: reorg, split notes from exocortex page.

The exocortex page was getting unwieldy, this makes more sense.
This commit is contained in:
Kyle Isom 2018-01-16 16:43:12 -08:00
parent 36ed6df77f
commit 6d4fb673ef
19 changed files with 363 additions and 0 deletions

97
lpn/ch01/notes.md Normal file
View File

@ -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".

50
lpn/ch02/notes.md Normal file
View File

@ -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."

24
lpn/ch03/descend.pl Normal file
View File

@ -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).

2
lpn/ch03/infrecur.pl Normal file
View File

@ -0,0 +1,2 @@
%% infinite recursion.
p :- p.

7
lpn/ch03/matroshka.pl Normal file
View File

@ -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).

162
lpn/ch03/notes.md Normal file
View File

@ -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
```

8
lpn/ch03/succ.pl Normal file
View File

@ -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).

13
lpn/ch03/travel.pl Normal file
View File

@ -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).