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