LPN: reorg, split notes from exocortex page.
The exocortex page was getting unwieldy, this makes more sense.
This commit is contained in:
24
lpn/ch03/descend.pl
Normal file
24
lpn/ch03/descend.pl
Normal 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).
|
||||
8
lpn/ch03/eating.pl
Normal file
8
lpn/ch03/eating.pl
Normal file
@@ -0,0 +1,8 @@
|
||||
is_digesting(X,Y) :- just_ate(X,Y).
|
||||
is_digesting(X,Y) :-
|
||||
just_ate(X,Z),
|
||||
is_digesting(Z,Y).
|
||||
|
||||
just_ate(mosquito,blood(john)).
|
||||
just_ate(frog,mosquito).
|
||||
just_ate(stork,frog).
|
||||
2
lpn/ch03/infrecur.pl
Normal file
2
lpn/ch03/infrecur.pl
Normal file
@@ -0,0 +1,2 @@
|
||||
%% infinite recursion.
|
||||
p :- p.
|
||||
7
lpn/ch03/matroshka.pl
Normal file
7
lpn/ch03/matroshka.pl
Normal 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
162
lpn/ch03/notes.md
Normal 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
8
lpn/ch03/succ.pl
Normal 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
13
lpn/ch03/travel.pl
Normal 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).
|
||||
Reference in New Issue
Block a user