├── _config.yml
├── CheatSheet.pdf
├── .gitmodules
├── CheatSheet.pl
├── README.md
└── CheatSheet.org
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-merlot
--------------------------------------------------------------------------------
/CheatSheet.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alhassy/PrologCheatSheet/HEAD/CheatSheet.pdf
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "CheatSheet"]
2 | path = CheatSheet
3 | url = https://github.com/alhassy/CheatSheet.git
4 |
--------------------------------------------------------------------------------
/CheatSheet.pl:
--------------------------------------------------------------------------------
1 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Facts%20---Nullary%20Relations][Facts ---Nullary Relations:1]]
2 | jasim_is_nice.
3 |
4 | % ?- jasim_is_nice. %⇒ true: We declared it so.
5 |
6 | it_is_raining. /* Another fact of our world */
7 |
8 | % ?- it_is_raining. %⇒ true
9 |
10 | eats(fred, mangoes).
11 | eats(bob, apples).
12 | eats(fred, oranges).
13 |
14 | % ?- eats(bob, apples). %⇒ true
15 |
16 | % Which foods are eaten by fred?
17 | % ?- eats(fred, what). %⇒ false; ‘what’ is name!
18 | % ?- eats(fred, What). %⇒ mangoes oranges
19 | %% Facts ---Nullary Relations:1 ends here
20 |
21 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Facts%20---Nullary%20Relations][Facts ---Nullary Relations:2]]
22 | % All men are mortal.
23 | mortal(X) :- man(X).
24 |
25 | % Socrates is a man.
26 | man(socrates).
27 |
28 | % Hence, he's expected to be mortal.
29 | % ?- mortal(socrates). %⇒ true
30 |
31 | % What about Plato?
32 | % ?- mortal(plato). %⇒ false, plato's not a man.
33 |
34 | % Let's fix that.
35 | man(plato).
36 |
37 | % Who is mortal?
38 | % ?- mortal(X). % ⇒ socrates plato
39 | %% Facts ---Nullary Relations:2 ends here
40 |
41 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Conjunction][Conjunction:1]]
42 | yum(pie).
43 | yum(apples).
44 | yum(maths).
45 |
46 | % ?- yum(Y), writeln(Y), fail. %⇒ pie apples maths false.
47 | %% Conjunction:1 ends here
48 |
49 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Arithmetic%20with%20~is~][Arithmetic with ~is~:1]]
50 | % ?- X = 3 + 2. %% X = 3 + 2
51 |
52 | % ?- X is 3 + 2. %% X = 5
53 |
54 | % ?- X is 6 / 3. %̄⇒ X = 2.
55 |
56 | % ?- X is 5 / 3. %̄⇒ X = 1.6666666666666667.
57 |
58 | % ?- X is 5 // 3. %̄⇒ X = 1.
59 |
60 | % ?- X is 5 mod 3. %̄⇒ X = 2.
61 | %% Arithmetic with ~is~:1 ends here
62 |
63 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Arithmetic%20with%20~is~][Arithmetic with ~is~:2]]
64 | % ?- name(woah_hello, X). %⇒ X = [119,111,97,104,95,104,101,108,108,111]
65 | % ?- name(woah, X). %⇒ X = [119,111,97,104]
66 | %% Arithmetic with ~is~:2 ends here
67 |
68 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Arithmetic%20with%20~is~][Arithmetic with ~is~:3]]
69 | % ?- atom_chars(nice, X). %⇒ X = [n, i, c, e].
70 | %% Arithmetic with ~is~:3 ends here
71 |
72 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Declaration%20Ordering%20Matters][Declaration Ordering Matters:1]]
73 | % Graph
74 | edge(a, b). edge(b ,c). edge(c, d).
75 |
76 | % Works
77 | path(X, X).
78 | path(X, Y) :- edge(Z, Y), path(X, Z).
79 | % ?- path(a, d). %⇒ true.
80 |
81 | % Fails: To find a path, we have to find a path, before an edge!
82 | % The recursive clause is first and so considerd before the base clause!
83 | path_(X, Y) :- path_(X, Z), edge(Z, Y).
84 | path_(X, X).
85 | % ?- path_(a, d). %⇒ loops forever!
86 | %% Declaration Ordering Matters:1 ends here
87 |
88 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*The%20Cut][The Cut:1]]
89 | a(X,Y) :- b(X), !, c(Y).
90 | b(1). b(2). b(3).
91 | c(1). c(2). c(3).
92 |
93 | % ?- a(X, Y). %⇒ X = 1 ∧ Y = 1, X = 1 ∧ Y = 2, X = 1 ∧ Y = 3
94 | %% The Cut:1 ends here
95 |
96 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*The%20Cut][The Cut:2]]
97 | d(X) :- e(X), !, f(X).
98 | e(1). e(2). e(3). f(2).
99 |
100 | % ?- not(d(X)). %⇒ “no solution” since only e(1) considered.
101 | % ?- d(2). %⇒ true, since no searching performed and 2 ∈ e ∩ f.
102 |
103 | d_no_cut(X) :- e(X), f(X).
104 | % ?- d_no_cut(X). %⇒ X = 2.
105 | %% The Cut:2 ends here
106 |
107 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*The%20Cut][The Cut:3]]
108 | g(X) :- h(X), !, i(X).
109 | g(X) :- j(X).
110 |
111 | h(1). h(4). i(3). j(4).
112 |
113 | % ?- g(X).
114 | %% The Cut:3 ends here
115 |
116 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*The%20Cut][The Cut:5]]
117 | sum_to(0, 0) :- !.
118 | sum_to(N, Res) :- M is N - 1, sum_to(M, ResM), Res is ResM + N.
119 |
120 | % ?- sum_to(1, X).
121 | %% The Cut:5 ends here
122 |
123 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*The%20Cut][The Cut:6]]
124 | sum_to_not(0, 0).
125 | sum_to_not(N, Res) :- N \= 0, M is N - 1, sum_to(M, ResM), Res is ResM + N.
126 |
127 | % ?- sum_to_not(5, X). %⇒ X = 15.
128 | %% The Cut:6 ends here
129 |
130 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*ADT:%20Pairs,%20Numbers,%20Lists,%20and%20Trees][ADT: Pairs, Numbers, Lists, and Trees:1]]
131 | % In Haskell: Person = Me | You | Them
132 | person(me).
133 | person(you).
134 | person(them).
135 |
136 | % In Haskell: Pair a b = MkPair a b
137 |
138 | pair(_, _).
139 |
140 | % ?- pair(1, "nice").
141 | % ?- pair(1, "nice") = pair(A, "nice"). %⇒ A = 1
142 |
143 | % In Haskell: Nat = Zero | Succ Nat
144 |
145 | nat(zero).
146 | nat(succ(N)) :- nat(N).
147 |
148 | % ?- nat(succ(succ(zero))).
149 |
150 | sum(zero, N, N).
151 | sum(succ(M), N, succ(S)) :- sum(M, N, S).
152 |
153 | % ?- Two = succ(succ(zero)), Four = succ(succ(succ(succ(zero)))), sum(Two, Two, Four).
154 | %% ADT: Pairs, Numbers, Lists, and Trees:1 ends here
155 |
156 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*ADT:%20Pairs,%20Numbers,%20Lists,%20and%20Trees][ADT: Pairs, Numbers, Lists, and Trees:2]]
157 | % In Haskell: Tree a = Leaf a | Branch (Tree a) (Tree a)
158 |
159 | tree(leaf(_)).
160 | tree(branch(L, R)) :- tree(L), tree(R).
161 |
162 | % ?- A = leaf(1), B = leaf(2), L = branch(A, B), R = branch(A, A), tree(branch(L, R)).
163 | %% ADT: Pairs, Numbers, Lists, and Trees:2 ends here
164 |
165 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*ADT:%20Pairs,%20Numbers,%20Lists,%20and%20Trees][ADT: Pairs, Numbers, Lists, and Trees:3]]
166 | % Head: (car (cons X Xs)) = X
167 | % Tail: (cdr (cons X Xs)) = Xs
168 | % Extensionality: (cons (car Xs) (cdr Xs)) = Xs, for non-null Xs.
169 |
170 | % We can just write the spec up to produce the datatype!
171 | % We simply transform /functions/ car and cdr into relations;
172 | % leaving the constructor, cons, alone.
173 |
174 | % What are lists?
175 | list(nil).
176 | list(cons(_, Xs)) :- list(Xs).
177 |
178 | null(nil).
179 |
180 | car(cons(X, Xs), X) :- list(Xs).
181 | cdr(cons(_, Xs), Xs) :- list(Xs).
182 |
183 | % ?- true.
184 | % - list(Ys), not(null(L)), list(cons(car(Ys, Y), cdr(Ys, L))). % loops.
185 |
186 | % ?- [1] = [1|[]].
187 | %% ADT: Pairs, Numbers, Lists, and Trees:3 ends here
188 |
189 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Built-in%20Lists][Built-in Lists:1]]
190 | % ?- ["one", two, 3] = [Head|Tail]. %⇒ Head = "one", Tail = [two, 3].
191 | % ?- ["one", two, 3] = [_,Second|_]. %⇒ Second = two.
192 | % ?- [[the, Y], Z] = [[X, hare], [is, here]]. %⇒ X = the, Y = hare, Z = [is, here]
193 | %% Built-in Lists:1 ends here
194 |
195 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Built-in%20Lists][Built-in Lists:2]]
196 | % Searching: x ∈ l?
197 | elem(Item, [Item|Tail]). % Yes, it's at the front.
198 | elem(Item, [_|Tail]) :- elem(Item, Tail). % Yes, it's in the tail.
199 |
200 | % ?- elem(one, [this, "is", one, thing]). %⇒ true
201 | % ?- elem(onE, [this, "is", one, thing]). %⇒ false
202 | %% Built-in Lists:2 ends here
203 |
204 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Built-in%20Lists][Built-in Lists:4]]
205 | % member is above, ‘elem’.
206 |
207 | append([], List2, List2).
208 | append([H|T], List2, [H|Append]) :- append(T, List2, Append).
209 |
210 | % ?- append([1,"two", three], [four, "5", "6"], Result).
211 |
212 | prefix([], List).
213 | prefix([H|T], [H|List]) :- prefix(T, List).
214 |
215 | % ?- prefix([1,2,three], [1, 2, three, four]).
216 | % ?- not(prefix([1,2,three], [1, 2])).
217 |
218 | nth0(0, [H|T], H).
219 | nth0(X, [_|T], E) :- Y is X - 1, nth0(Y, T, E).
220 |
221 | % ?- nth0(2, [one, two, three], X).
222 | % ?- not(nth0(2, [one, two], X)).
223 |
224 | last([H],H).
225 | last([_|T], L) :- last(T, L).
226 |
227 | % ?- last([1,2,3], L).
228 | % ?- last([1,2], L).
229 | % ?- not(last([], L)).
230 |
231 | mylength([], 0).
232 | mylength([H|T], Res) :- length(T, L), Res is L + 1.
233 |
234 | % ?- mylength([1,2,3], L).
235 |
236 | % count(E, L, N) ≡ E occurs N times in L
237 | count(E, [], 0).
238 | count(E, [E|T], Res) :- count(E, T, N), Res is N + 1.
239 | count(E, [_|T], N) :- count(E, T, N).
240 |
241 | % ?- count(2, [1,2,1,3,2], N).
242 |
243 | % For each element x of list1, let n1 and n2 be the number of times x occurs in list1 and list2; they're bag-equal if n1 = n2. Note: elem requires a non-empty list.
244 | %% Built-in Lists:4 ends here
245 |
246 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Using%20Modules][Using Modules:1]]
247 | use_module(library(clpfd)).
248 |
249 | % ?- all_distinct([1,"two", two]).
250 | %% Using Modules:1 ends here
251 |
252 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Higher-order][Higher-order:1]]
253 | colour(bike, red).
254 | colour(chair, blue).
255 |
256 | % Crashes!
257 | % is_red(C, X, Y) :- C(X, Y)
258 |
259 | % Works
260 | is_red(C, X, Y) :- call(C, X, Y).
261 |
262 | % ?- is_red(colour, bike, X). %⇒ X = red.
263 | %% Higher-order:1 ends here
264 |
265 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Higher-order][Higher-order:2]]
266 | % ?- p(a, b, c) =.. Y. %⇒ Y = [p, a, b, c].
267 | % ?- Y =.. [p, a, b, c]. %⇒ Y = p(a, b, c).
268 | %% Higher-order:2 ends here
269 |
270 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*~Print,%20var,%20nonvar~][~Print, var, nonvar~:1]]
271 | % ?- var(Y). %⇒ true
272 | % ?- Y = 2, var(Y). %⇒ false
273 | % ?- Y = 2, nonvar(Y). %⇒ true
274 | %% ~Print, var, nonvar~:1 ends here
275 |
276 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*~Print,%20var,%20nonvar~][~Print, var, nonvar~:2]]
277 | % ?- arg(2, foo(x, y), y). %⇒ true
278 | %% ~Print, var, nonvar~:2 ends here
279 |
280 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Meta-Programming][Meta-Programming:1]]
281 | test(you, me, us).
282 | test(A, B, C) :- [A, B, C] = [the, second, clause].
283 |
284 | % ?- clause(test(Arg1, Arg2, Arg3), Body).
285 | % ⇒ ‘Body’ as well as ‘Arg𝒾’ are unified for each clause of ‘test’.
286 | %% Meta-Programming:1 ends here
287 |
288 | %% [[file:~/PrologCheatSheet/CheatSheet.org::*Meta-Programming][Meta-Programming:2]]
289 | % interpret(G) succeeds as a goal exactly when G succeeds as a goal.
290 |
291 | % Goals is already true.
292 | interpret(true) :- !.
293 |
294 | % A pair of goals.
295 | interpret((G, H)) :- !, interpret(G), interpret(H).
296 |
297 | % Simple goals: Find a clause whose head matches the goal and interpret its subgoals.
298 | interpret(Goal) :- clause(Goal,Subgoals), interpret(Subgoals).
299 |
300 | % ?- interpret(test(A, B, C)).
301 | %% Meta-Programming:2 ends here
302 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
PrologCheatSheet
2 |
3 | Basics of relational programming with Prolog
4 | —PROgramming in LOGic
5 | ^\_^
6 |
7 | [Try Prolog online](https://swish.swi-prolog.org/p/algorex_prolog.pl)
8 |
9 | **The listing sheet, as PDF, can be found
10 | [here]()**,
11 | while below is an unruly html rendition.
12 |
13 | This reference sheet is built around the system
14 | .
15 |
16 |
17 | # Table of Contents
18 |
19 | 1. [Administrivia](#org944e9a2)
20 | 2. [Syntax](#org1631a81)
21 | 1. [`name` and `atom_chars`](#org01cff87)
22 | 3. [Facts & Relations](#org11a6a80)
23 | 4. [Mixfix Syntax](#org7e5c51a)
24 | 5. [Trace & Backtracking](#org7b75a05)
25 | 6. [What is a Prolog Program Exactly?](#orgd201c75)
26 | 1. [One point rule](#org67c9d9a)
27 | 2. [Overloading](#org0bf2d9a)
28 | 7. [Modus Ponens — Computation ≈ Deduction](#org3dc81b4)
29 | 8. [Conjunction ≈ Constraints — Disjunction ≈ Alternatives](#org0815789)
30 | 9. [Unification](#orgaabb8fb)
31 | 1. [Operational Semantics](#org15dfa67)
32 | 2. ['symbol' = symbol](#org8ef5c60)
33 | 3. [Unification performs no simplification, whence no arithmetic](#orga3a1299)
34 | 10. [Algebraic Datatypes](#org6447078)
35 | 11. [Arithmetic with `is` —Using Modules](#org4994886)
36 | 1. [Using Modules](#org86bbea7)
37 | 12. [Lists](#orge54ab30)
38 | 13. [Declaration Ordering Matters —Recursion](#org9e00a34)
39 | 14. [The Cut](#org0df11fd)
40 | 1. [Examples](#orgba67465)
41 | 2. [Disjoint Clauses](#org23e01e5)
42 | 3. [Conditional](#org0e85739)
43 | 4. [Cut-fail Combination](#orgdbae64d)
44 | 5. [Good Exercise](#org84fe2d7)
45 | 15. [Higher-order Support with `call`](#orgc8294a3)
46 | 16. [Meta-Programming](#org3072386)
47 | 1. [`Print, var, nonvar, arg`](#org17ed3b0)
48 | 17. [Reads](#orge425102)
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | # Administrivia
67 |
68 | *Everything is a relation!* —I.e., a table in a database!
69 |
70 | Whence programs are [unidirectional](https://blog.algorexhealth.com/2018/11/a-practo-theoretical-introduction-to-logic-programming/) and can be ‘run in reverse’:
71 | Input arguments and output arguments are the same
72 | thing! Only perspective shifts matter.
73 |
74 | For example, defining a relation `append(XS, YS, ZS)`
75 | *intended* to be true precisely when `ZS` is the catenation of `XS` with `YS`,
76 | gives us three other methods besides being a predicate itself!
77 | List construction: `append([1, 2], [3, 4], ZS)` ensures `ZS` is the catenation list.
78 | List subtraction: `append([1,2], YS, [1, 2, 3, 4])` yields all solutions `YS` to
79 | the problem `[1, 2] ++ YS = [1, 2, 3, 4]`.
80 | Partitions: `append(XS, YS, [1, 2, 3, 4])` yields all pairs of lists that catenate
81 | to `[1,2, 3, 4]`. **Four methods for the price of one!**
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | | Prolog is PROgramming in LOGic. |
92 |
93 |
94 |
95 |
96 | In Prolog, the task of the programmer is simply to *describe* problems
97 | —write down, logically, the situation— rather than telling the computer
98 | what to do, then obtains information by asking questions
99 | —the logic programming system *figures out how* to get the answer.
100 |
101 | - Prolog is declarative: A program is a collection of ‘axioms’ from which ‘theorems’
102 | can be proven. For example, consider how sorting is performed:
103 |
104 | - Procedurally: Find the minimum in the remainder of the list, swap it with the head
105 | of the list; repeat on the tail of the list.
106 |
107 | - Declaratively: `B` is the sorting of `A` *provided* it is a permutation of `A` and it is
108 | ordered.
109 |
110 | Whence, a program is a theory and computation is deduction!
111 |
112 | - `swipl -s myprogram.pl` –Load your program into a REPL, `?-….`
113 | - `make.` –Reload your program.
114 | - `halt.` –Exit the REPL.
115 | - `consult('CheatSheet.pl').` –Load the contents of the given file as
116 | the new knowledge base.
117 | - `assert((⋯)).` –Add a new rule to the knowledge base, from within the REPL.
118 | Use `retract((⋯))` to remove rules from the knowledge base.
119 | - `assert` is useful when we want to [cache](http://cs.union.edu/~striegnk/learn-prolog-now/html/node94.html#sec.l11.database.manip) computations.
120 | - `listing.` –Display the contents of the current knowledge base; i.e.,
121 | what Prolog ‘knows’.
122 | - `listing(name)`. –List all information in the knowledge base about
123 | the `name` predicate.
124 |
125 |
126 |
127 |
128 | # Syntax
129 |
130 | There are three types of terms:
131 |
132 | - Constants: Numbers such as -24, and atoms such as `jasim`, `'hello world'`,
133 | `'&^%@$ &*',` and `' '` —a space in quotes.
134 | - Variables: Words starting with a capital letter or an underscore.
135 | - The variable `_` is called the *anonymous variable*.
136 |
137 | It's for when we need a variable, say when pattern matching,
138 | but don't care about the value.
139 |
140 | - Structures: Terms of the form `functor(term₁,...,termₙ)`.
141 |
142 |
143 |
144 |
145 | ## `name` and `atom_chars`
146 |
147 | The characters between single quotes are the *name* of an atom
148 | and so Prolog admits `symbol = 'symbol'` as true.
149 |
150 | - Atoms, or nullary predicates, are represented as a lists of numbers; ASCII codes.
151 | - We can use this to compare two atoms lexicographically.
152 | - We can obtain the characters in an atom by using the built-in `atom_chars`.
153 |
154 | ?- name(woah, X). %⇒ X = [119,111,97,104]
155 | ?- atom_chars(nice, X). %⇒ X = [n, i, c, e].
156 |
157 |
158 |
159 |
160 | # Facts & Relations
161 |
162 | We declare relations by having them begin with a lowercase letter;
163 | variables are distinguished by starting with a capital letter.
164 |
165 |
166 | /* Some facts of our world */
167 | jasim_is_nice.
168 | it_is_raining.
169 |
170 | % ?- jasim_is_nice.
171 | % ⇒ true: We declared it so.
172 |
173 | eats(fred, mangoes).
174 | eats(bob, apples).
175 | eats(fred, oranges).
176 |
177 | % Which foods are eaten by fred?
178 | % ?- eats(fred, what).
179 | %⇒ false; “what” is a name!
180 | % ?- eats(fred, What). %⇒ mangoes oranges
181 |
182 |
183 |
184 | Relational constraints are formed using `:-`, which acts as the “provided”, ⇐,
185 | operator from logic. Read `P :- Q` as *P is true, provided Q is true.*
186 |
187 |
188 | % All men are mortal.
189 | mortal(X) :- man(X).
190 |
191 | % Socrates is a man.
192 | man(socrates).
193 |
194 | % Hence, he's expected to be mortal.
195 | % ?- mortal(socrates). %⇒ true
196 |
197 | % What about Plato?
198 | ?- mortal(plato).
199 | %⇒ false, plato's not a man.
200 |
201 | % Let's fix that … in the REPL!
202 | ?- assert((man(plato))).
203 |
204 | % Who is mortal?
205 | ?- mortal(X). % ⇒ socrates plato
206 |
207 |
208 |
209 |
210 |
211 |
212 | # [Mixfix Syntax](http://cs.union.edu/~striegnk/learn-prolog-now/html/node84.html#subsec.l9.operators.def)
213 |
214 |
215 | It may feel awkward to write `father_of(homer, bart)` and instead prefer
216 | `homer father_of bart`. We may declare relations to be prefix, infix, or postfix
217 | with patterns `xf`, `xfx`, and `fx` respectively. For left associativity
218 | we use pattern `yfx` and use `xfy` for right associativity.
219 |
220 | :- op(35,xfx,father_of).
221 |
222 | father_of(me, you).
223 | homer father_of bart.
224 | homer father_of lisa.
225 |
226 |
227 |
228 | - Precedence, or binding power, is lowest at 1200 and highest at 0.
229 | - Note: `father_of(X,Y) = X father_of Y` is true.
230 |
231 | We may learn about existing operators too;
232 |
233 | e.g., `?- current_op(Prec, Fixity, =:=)` ^\_^
234 |
235 |
236 |
237 |
238 | # Trace & Backtracking
239 |
240 | We can see what Prolog does at each step of a computation by invoking
241 | `trace`; we turn off this feature with `notrace.`
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 | | *This’ an excellent way to learn how Prolog proof search works! (Debugging!)* |
252 |
253 |
254 |
255 |
256 |
257 | Suppose we have the following database.
258 |
259 | q(1). q(2). q(3).
260 | r(2). r(3).
261 | p(X) :- q(X), r(X).
262 |
263 | With trace, query `p(X)` and press
264 | *SPACE* each time to see what
265 | Prolog is doing.
266 | At one point, the goal `r(1)` will
267 | *fail* and that choice \(X = 1\)
268 | will be redone with the next possibility
269 | for `q`, namely \(X = 2\).
270 |
271 |
272 |
273 | The line marked `redo` is when Prolog realizes its taken the wrong
274 | path, and backtracks to instantiate the variable to 2.
275 |
276 | Operationally, query `p(X)` is answered by:
277 |
278 | 1. Find match for the first goal: `q` at `1`.
279 | 2. Then see if matches the second: `r` at `1`.
280 | 3. (Redo) If not, find another match for the first: `q` at `2`.
281 | 4. See if this matches the second, `r`.
282 | 5. Etc.
283 |
284 | - `findall(X, Goal, L)` succeeds if `L` is the list of all those `X`'s for
285 | which `Goal` holds.
286 |
287 | - `fail/0` immediately fails when encountered. Remember: Prolog tries to
288 | backtrack when its fails; whence `fail` can be viewed as an
289 | instruction to force backtracking.
290 |
291 | The opposite of forcing backtracking is to block it, which is done
292 | with ‘cut’ `!` —see below.
293 |
294 |
295 |
296 |
297 | # What is a Prolog Program Exactly?
298 |
299 | A program *denotes* all true facts derivable from its clauses using
300 | **modus ponens, unification, term rewriting, and logical or-&-and**
301 | for the execution model.
302 |
303 | Hidden Quantifiers:
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 | | Syntax |
316 | Semantics |
317 |
318 |
319 |
320 |
321 | | `head(X) :- body(X,Y).` |
322 | \(∀ X.\, head(X) \,⇐\, ∃ Y.\, body(X,Y)\) |
323 |
324 |
325 |
326 |
327 | | `?- Q(X)` |
328 | \(∃ X.\, Q(X)\) |
329 |
330 |
331 |
332 |
333 | 1. “ `head(X)` is true provided there's some `Y` such that `body(X,Y)` is true ”
334 | - `head.` is an abbreviation for `head :- true.`
335 | - Indeed, \(p \;≡\; (p ⇐ true)\).
336 | 2. “ Is there an `X` so that `Q(X)` is true? ”
337 |
338 |
339 |
340 |
341 | ## One point rule
342 |
343 | “One-Point Rule”: Provided `X` is a fresh variable,
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 | | `f(⋯X⋯) :- X = ℰ𝓍𝓅𝓇.` |
358 | ≈ |
359 | `f(⋯ℰ𝓍𝓅𝓇⋯).` |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 | ## Overloading
368 |
369 | *Overloading!* Predicates of different arities are considered different.
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 | | Documentation Convention: |
386 | `f/N` |
387 | ≈ |
388 | *relation `f` takes `N`-many arguments* |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 | # Modus Ponens — Computation ≈ Deduction
397 |
398 | The logical rule \(p ∧ (p ⇒ q) \;⇒\; q\) says if we have \(p\), and from
399 | that we know we can get a \(q\), then we have a \(q\). From the following program
400 | on the left, we get `q(a)` is true.
401 |
402 |
403 | p(a).
404 | q(X) :- p(X).
405 |
406 | We *rewrite* term `X` with atom `a` to obtain `q(a) :- p(a)` from the second rule,
407 | but we know `p(a)`, and so we have *computed* the new fact `q(a)` by using the
408 | deduction rule modus ponens.
409 |
410 |
411 |
412 |
413 |
414 |
415 | # Conjunction ≈ Constraints — Disjunction ≈ Alternatives
416 |
417 | Conjunction: `p(X), q(X)` means “let `X` be *a* solution to `p`, then use it in query `q`.”
418 |
419 |
420 | Operational semantics: Let `X` be the first solution declared, found,
421 | for `p`, in the user's script, then try `q`; if it fails, then *backtrack*
422 | and pick the next declared solution to `p`, if any, and repeat until `q`
423 | succeeds —if possible, otherwise fail.
424 |
425 | yum(pie).
426 | yum(apples).
427 | yum(maths).
428 |
429 | % ?- yum(Y), writeln(Y), fail.
430 | %⇒ pie apples maths false.
431 |
432 |
433 |
434 | “Fail driven loop” `p(X), print(X), fail.` gets a solution to `p`, prints
435 | it, then fails thereby necessitating a backtrack to obtain a
436 | different solution `X` for `p`, then repeats. In essence, this is prints
437 | all solutions to `p`.
438 |
439 | “Let Clauses”: Provided `X` is a fresh variable,
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 | | `⋯ℰ𝓍𝓅𝓇⋯ℰ𝓍𝓅𝓇⋯` |
454 | ≈ |
455 | `X = ℰ𝓍𝓅𝓇, ⋯X⋯X⋯` |
456 |
457 |
458 |
459 |
460 | A Prolog program is the conjunction of all its clauses, alternatives ‘;’.
461 |
462 |
463 | % (head ⇐ body₁) ∧ (head ⇐ body₂)
464 | head :- body₁.
465 | head :- body₂.
466 | ≈
467 | % head ⇐ body₁ ∨ body₂
468 | head :- body₁ ; body₂.
469 |
470 | Read ‘⇐’ as ‘≥’, and ‘∨’ as maximum, then the following is the
471 | “characterisation of least upper bounds”.
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 | | |
484 | \((p ⇐ q) ∧ (p ⇐ r)\) |
485 |
486 |
487 |
488 |
489 | | ≡ |
490 | |
491 |
492 |
493 |
494 |
495 | | |
496 | \(p ⇐ (q ∨ p)\) |
497 |
498 |
499 |
500 |
501 |
502 |
503 | “And binds stronger than Or”: `a,b;c ≈ (a,b);c`.
504 |
505 |
506 |
507 |
508 | # [Unification](http://cs.union.edu/~striegnk/learn-prolog-now/html/node15.html)
509 |
510 | A program can be written by having nested patterns, terms, then we use
511 | matching to pull out the information we want!
512 |
513 | Two terms *match* or *unify*, if they are equal or if they contain variables that
514 | can be instantiated in such a way that the resulting terms are equal.
515 |
516 | - **Unification:** Can the given terms be made to represent the same structure?
517 | - This is how type inference is made to work in all languages.
518 |
519 | - **Backtracking:** When a choice in unification causes it to fail, go back to the
520 | most recent choice point and select the next available choice.
521 | - Nullary built-in predicate `fail` always fails as a goal and causes backtracking.
522 |
523 |
524 |
525 |
526 | ## Operational Semantics
527 |
528 |
529 | The unification predicate is `=/2`. It can be written with the usual
530 | notation `=(L, R)` but can also be written infix `L = R`.
531 |
532 | % Query: Who is loved by Jay?
533 | ?- loves(jay, X) = loves(jay, kathy).
534 | % ⇒ X = kathy
535 |
536 |
537 |
538 | Operationally `ℒ = ℛ` behaves as follows:
539 |
540 | 1. If either is an unbound variable, assign it to the other one.
541 | - A constant unifies only with itself.
542 | - A variable unifies with anything.
543 | 2. Otherwise, they are both terms.
544 | - Suppose \(ℒ ≈ f(e₁,…,eₙ)\) and \(ℛ ≈ g(d₁,…,dₘ)\).
545 | - If `f` is different from `g`, or `n` different from `m`, then crash.
546 | - Recursively perform `eᵢ = dᵢ`.
547 |
548 | Ensure the variable instantiations are compatible in that a
549 | variable is associated with at most one value —which is
550 | not true in `f(1,2) = f(X,X).`
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 | | **Thus variables are single ‘assignment’!** |
561 |
562 |
563 |
564 |
565 | Exception! Each occurrence of the anonymous variable `_`
566 | is independent: Each is bound to something different.
567 |
568 | 3. If two terms can't be shown to match using the above clauses,
569 | then they don't match.
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 | | *Unification lets us solve equations!* It lets us **compute!** |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 | ## 'symbol' = symbol
588 |
589 | The query `'symbol' = symbol` is true since both are considered to be the same
590 | atom. Whereas `'2' = 2` is false since `'2'` is a symbolic atom but `2` is a number.
591 |
592 | The *discrepancy predicate* `\=/2` succeeds when its arguments don't unify;
593 | e.g., `'5' \= 5` is true.
594 |
595 |
596 |
597 |
598 | ## Unification performs no simplification, whence no arithmetic
599 |
600 |
601 | Unification performs no simplification, whence no arithmetic.
602 | This means, for example, we can form pairs by sticking an infix operator between two items; moreover we can form distinct kinds of pairs by using different operators.
603 |
604 | ?- C + "nice" = woah + Z.
605 | C = woah, Z = "nice".
606 |
607 | % ‘+’ and ‘/’ are different,
608 | % so no way to make these equal.
609 | ?- C + "nice" = woah / Z.
610 | false.
611 |
612 |
613 |
614 |
615 |
616 |
617 | # Algebraic Datatypes
618 |
619 | Uniform treatment of all datatypes as predicates! Enumerations, pairs, recursives:
620 |
621 |
622 | Haskell
623 |
624 | data Person = Me | You | Them
625 |
626 |
627 |
628 | data Pair a b = MkPair a b
629 |
630 | data Nat = Zero | Succ Nat
631 |
632 |
633 | sum Zero n = n
634 | sum (Succ m) n = Succ (sum m n)
635 |
636 | Prolog
637 |
638 | person(me).
639 | person(you).
640 | person(them).
641 |
642 | pair(_, _).
643 |
644 | nat(zero).
645 | nat(succ(N)) :- nat(N).
646 |
647 | sum(zero, N, N).
648 | sum(succ(M), N, succ(S))
649 | :- sum(M, N, S).
650 |
651 |
652 |
653 | Exercise: Form binary trees.
654 |
655 |
656 |
657 |
658 | # Arithmetic with `is` —Using Modules
659 |
660 | Use `is` to perform arithmetic with `+, -, *, /, **, mod`, and
661 | `//` for integer division.
662 |
663 | % How do we make this equation equal?
664 | ?- X = 3 + 2.
665 | % ⇒ X = 3 + 2; this choice of variables make its equal!
666 |
667 | % Everything is a term! Terms don't ‘compute’!
668 | ?- +(3, 2) = 3 + 2. % ⇒ true
669 | ?- +(3, 2) = 6 - 1. % ⇒ false
670 |
671 |
672 | ?- X is 3 + 2. % ⇒ X = 5
673 | ?- 5 is 6 - 1. % ⇒ true
674 | ?- 5 is X. % ⇒ CRASH!
675 | ?- 3 + 2 is 6 - 1. %⇒ CRASH!
676 |
677 | ?- +(3, 2) =:= 6 - 1. % ⇒ true
678 | ?- 1 =:= sin(pi/2). % ⇒ true
679 | ?- X =:= 3 + 2. % ⇒ CRASH!
680 | ?- X = 2, Y = 3, X + Y =:= 5. % ⇒ true
681 |
682 |
683 |
684 | - `is` takes a *variable, or a numeric constant,* and an arithmetical
685 | expression as arguments.
686 | - `L is R` means “ unify `L` with the result of simplifying `R` ”
687 | - If `R` mentions an unbound variable, crash!
688 | - `=:=` has both arguments as *concrete terms*, it evaluates them and compares the results.
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 | | `𝓁 =:= 𝓇` |
703 | ≈ |
704 | `L is 𝓁, R is 𝓇, L = R`. |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 | ## Using Modules
713 |
714 |
715 |
716 |
717 | The [Constraint Logic Programming over Finite Domains](http://www.swi-prolog.org/pldoc/man?section=clpfd) library provides a number of
718 | useful functions, such as `all_distinct` for checking a list has unique elements.
719 |
720 | See [here](http://www.swi-prolog.org/pldoc/man?section=clpfd-sudoku) for a terse solution to Sudoku.
721 |
722 | In particular, `=:=` is too low level —e.g., it doesn't admit unbound variables—
723 | instead one uses `clpfd`'s `#=/2` predicate.
724 |
725 | Likewise we could use `in` to check if a number is in a particular range, or instead use `#>/2` and `#2`.
726 |
727 | use_module(library(clpfd)).
728 |
729 | ?- all_distinct([1,"two", two]).
730 |
731 | ?- X + 2 #= 3. %⇒ X = 1
732 | ?- 1 + Y #= 3. %⇒ Y = 2.
733 | ?- X #= Y. %⇒ Also works ;-)
734 |
735 | ?- 2 in 0..3. %⇒ true.
736 | ?- 3 #> X, 0 #< X. %⇒ X in 1..2.
737 |
738 | % All parititions of number N ^_^
739 | ?- N = 5, between(0, N, X),
740 | between(0, N, Y), X + Y #= N.
741 |
742 |
743 |
744 |
745 |
746 |
747 | # Lists
748 |
749 | Lists are enclosed in brackets, separated by commas, and can be split
750 | up at any point by using cons “|”. The empty list is `[]`.
751 |
752 | ?- ["one", two, 3] = [Head|Tail].
753 | %⇒ Head = "one", Tail = [two, 3].
754 |
755 | ?- ["one", two, 3] = [_,Second|_].
756 | %⇒ Second = two.
757 |
758 | ?- [[the, Y], Z] = [[X, hare], [is, here]].
759 | %⇒ X = the, Y = hare, Z = [is, here]
760 |
761 | Searching: \(x ∈ l\)?
762 |
763 | elem(Item, [Item|Tail]). % Yes, it's at the front.
764 | elem(Item, [_|Tail]) :- elem(Item, Tail). % Yes, it's in the tail.
765 |
766 | % ?- elem(one, [this, "is", one, thing]). %⇒ true
767 | % ?- elem(onE, [this, "is", one, thing]). %⇒ false
768 |
769 | See [here](http://www.swi-prolog.org/pldoc/man?section=lists) for the list library, which includes:
770 |
771 |
772 | member(element, list)
773 | append(list1, list2, lists12)
774 | prefix(part, whole)
775 | nth0(index, list, element)
776 | last(list, element)
777 | length(list, number)
778 | reverse(list1, list2)
779 | permutation(list1, list2)
780 | sum_list(list, number)
781 | max_list(list, number)
782 | is_set(list_maybe_no_duplicates)
783 |
784 | In Haskell, we may write `x:xs`, but trying that here forces us to write
785 | `[X|XS]` or `[X|Xs]` and accidentally mismatching the capitalisation of the ‘s’
786 | does not cause a compile-time error but will yield an unexpected logical error
787 | –e.g., in the recursive clause use `Taill` instead of `Tail`.
788 | As such, prefer the `[Head|Tail]` or `[H|T]` naming.
789 |
790 |
791 |
792 | Exercise: Implement these functions.
793 |
794 | Hint: Arithmetic must be performed using `is`.
795 |
796 |
797 |
798 |
799 | # Declaration Ordering Matters —Recursion
800 |
801 | Prolog searches the knowledge base from top to bottom, clauses from
802 | left to right, and uses backtracking to recover from bad choices.
803 |
804 | When forming a recursive relation, ensure the base case, the
805 | terminating portion, is declared before any portions that require
806 | recursion. Otherwise the program may loop forever.
807 |
808 | Unification is performed using depth-first search using the order of
809 | the declared relationships. For example, the following works:
810 |
811 | % Acyclic graph: a ⟶ b ⟶ c ⟶ d
812 | edge(a, b). edge(b ,c). edge(c, d).
813 |
814 | % Works
815 | path(X, X).
816 | path(X, Y) :- edge(Z, Y) % Can we get to Y from some intermediary Z?
817 | , path(X, Z). % Can we get to the intermediary Z from X?
818 | % ?- path(a, d). %⇒ true.
819 |
820 | % Fails: To find a path, we have to find a path, before an edge!
821 | % The recursive clause is first and so considerd before the base clause!
822 | path_(X, Y) :- path_(X, Z), edge(Z, Y).
823 | path_(X, X).
824 | % ?- path_(a, d). %⇒ loops forever!
825 |
826 |
827 |
828 |
829 | # The Cut
830 |
831 | Automatic backtracking is great, but can be a waste of time exploring
832 | possibilities that lead nowhere. The atom *cut*, `!`, offers a way to
833 | control how Prolog looks for solutions:
834 | It always succeeds with a side-effect of committing to any choices made thus far
835 | —including variable instantiations **and** rule, clause, chosen—
836 | whence ignoring any other possible branches and no backtracking!
837 |
838 | `q :- p₁, …, pₙ, !, r₁, …, rₘ`
839 | ⇒ Once we reach the cut, we're commited to the choices made when evaluating the `pᵢ`,
840 | but we are free to backtrack among the `rᵢ` **and** we may backtrack among the alternatives
841 | for choices that were made before reaching goal `q`. Here's an example.
842 |
843 |
844 | i(1). i(2).
845 | j(1). j(2). j(3).
846 |
847 | k(X, Y) :- i(X), !, j(Y).
848 |
849 | l(X,Y) :- k(X,Y).
850 | l(0,0).
851 |
852 |
853 |
854 | Query `l(X, Y)` yields
855 | solutions 1-1, 1-2, 1-3, and 0-0.
856 | Notice that `X = 0, Y = 0` is not
857 | truthified by by the first clause of `l`
858 | but the choice of clause happened before the `k`-clause
859 | containing the cut `!` and so backtracking may pick another `l`-clause.
860 | Notice that without the cut, we have the extra solutions 2-1, 2-2, 2-3
861 | which are “cut out” by `!` since `i(1)` is the choice we committed to for `X = 1`
862 | and we can backtrack for `Y` only since it comes after the cut.
863 |
864 | Suppose `x₁` is the first solution found for `p`, then:
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 | | `p(X), q(Y)` |
879 | ≈ |
880 | \(\{ (x, y) ❙ p\, x \,∧\, q\, y\}\) |
881 |
882 |
883 |
884 |
885 | | `p(X), !, q(Y)` |
886 | ≈ |
887 | \(\{ (x₁, y) ❙ q\, y\}\) |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 | ## Examples
896 |
897 | Remember, the cut not only commits to the instantiations so far, but
898 | also commits to the clause of the goal in which it occurs, whence no
899 | other clauses are even tried!
900 |
901 | g(X) :- h(X), !, i(X).
902 | g(X) :- j(X).
903 |
904 | h(1). h(4). i(3). j(2).
905 |
906 | % ?- g(X). %⇒ fails
907 |
908 | There are two clauses to prove `g`, by default we pick the first one.
909 | Now we have the subgoal `h`, for which there are two clauses and we select
910 | the first by default to obtain `X = 1`. We now encounter the cut which means
911 | we have committed to the current value of `X` and the current clause to prove `g`.
912 | The final subgoal is `i(1)` which is false. Backtracking does not allow us to select
913 | different goals, and it does not allow us to use the second clause to prove `g`.
914 | Whence, `g(X)` fails. Likewise we fail for `g(4)`. Note that if we had failed `h`
915 | before the cut, as is the case with `g(2)`, then we fail that clause before encountering
916 | the cut and so the second rule is tried.
917 |
918 |
919 |
920 |
921 | ## Disjoint Clauses
922 |
923 | When there are disjoint clauses, i.e., only one succeeds, then if
924 | backtracking is forced at some point, trying other cases is a waste
925 | of time since only one clause, say the first one, succeeds. An
926 | example of this would be the maximum function or the \(\sum_{i=0}^n i\) function.
927 |
928 |
929 | max_(X, Y, Y) :- X =< Y.
930 | max_(X, Y, X) :- X > Y.
931 |
932 | % ?- trace.
933 | % ?- max_(3, 4, Y).
934 | % ⇒ Wastes time trying both clauses.
935 |
936 | max(X, Y, Y) :- X =< Y, !.
937 | max(X, Y, X) :- X > Y.
938 |
939 | % ?- trace.
940 | % ?- max(3, 4, Y).
941 | % ⇒ Only first clause is tried ^_^
942 |
943 | sum_to(0, 0).
944 | sum_to(N, Res) :- M is N - 1,
945 | sum_to(M, ResM),
946 | Res is ResM + N.
947 |
948 | % Example execution
949 | % ?- sum_to(1, X).
950 | % ⇒ Loops forever: Both clauses apply!
951 |
952 | % The fix is to mark the
953 | % first clause as a “base case”.
954 | sum_to(0, 0) :- !.
955 |
956 |
957 |
958 | The resulting code gives the *same* results but is more *efficient*.
959 | Such cuts are called *green cuts*. Changes to a program that *depend*
960 | on a cut rather than the logic are called *red cuts* and are best avoided
961 | —e.g., `maxNo(X, Y, Y) :- X =< Y, !. maxNo(X, Y, X).` works by relying on the cut:
962 | It works with variables, but `maxNo(2, 3, 2)` matches the second clause unconditionally
963 | even though 2 is not the maximum of 2 and 3!
964 |
965 | - Cut at the end ⇒ Don't consider any more clauses of the current predicate.
966 |
967 |
968 |
969 |
970 | ## Conditional
971 |
972 | **Lazy Conditional**
973 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 | | `A -> B; C` |
985 | If `A` is true, then prove `B` and ignore `C`; else prove `C` and ignore `B`. |
986 |
987 |
988 |
989 |
990 | - The “; C” portion is *optional* and `C` defaults to `fail`.
991 | - We can also nest conditionals: `A₁ -> B₁; ⋯; Aₙ -> Bₙ; C` —again, `C` is optional.
992 |
993 | *We may use this form when we have disjoint conditions `Aᵢ`!*
994 |
995 | However, using multiple clauses is preferable as it clearly separates concerns.
996 |
997 |
998 |
999 |
1000 | ## Cut-fail Combination
1001 |
1002 | Suppose we want all solutions to `p` except `e`, then we write:
1003 |
1004 | all_but_e(X) :- X = e, !, fail.
1005 | all_but_e(X) :- p(X).
1006 |
1007 | When we pose the query `all_but_e(e)`, the first rule applies, and we
1008 | reach the cut. This commits us to the choices we have made, and in
1009 | particular, blocks access to the second rule. But then we hit
1010 | `fail`. This tries to force backtracking, but the cut blocks it, and so
1011 | our query fails —as desired.
1012 |
1013 | We can package up this red cut into a reusable form, ‘negation as failure’:
1014 |
1015 | % neg(Goal) succeeds iff Goal fails.
1016 | neg(Goal) :- Goal, !, fail.
1017 | neg(Goal).
1018 |
1019 | all_but_e(X) :- p(X), neg(X = e).
1020 |
1021 | The built-in prefix operator `\+` is negation as failure
1022 | —you may use `not(⋯)` but must use the parens and no space before them.
1023 |
1024 |
1025 |
1026 |
1027 |
1028 |
1029 |
1030 |
1031 |
1032 | | *Remember: Order matters with Prolog's conjunction*! |
1033 |
1034 |
1035 |
1036 |
1037 | Hence, `\+ X = e, p(X)` always fails —see `neg` above—
1038 | but `p(X), \+ X = e` yields all solutions to `p` except `e`.
1039 |
1040 |
1041 |
1042 |
1043 | ## Good Exercise
1044 |
1045 | Comprehension Exercise: With the left-side database, answer the right-side queries.
1046 |
1047 |
1048 | p(1).
1049 | p(2) :- !.
1050 | p(3).
1051 |
1052 | ?- p(X).
1053 | ?- p(X), p(Y).
1054 | ?- p(X), !, p(Y).
1055 |
1056 |
1057 |
1058 |
1059 |
1060 |
1061 |
1062 | # Higher-order Support with `call`
1063 |
1064 |
1065 | Prolog is limited to first-order logic: We cannot bind variables to relations.
1066 |
1067 | Prolog *indirectly* supports higher-order rules.
1068 |
1069 | colour(bike, red).
1070 | colour(chair, blue).
1071 |
1072 | % Crashes!
1073 | % is_red(C, X, Y) :- C(X, Y)
1074 |
1075 | % Works
1076 | is_red(C, X, Y) :- call(C, X, Y).
1077 |
1078 | % ?- is_red(colour, bike, X).
1079 | %⇒ X = red.
1080 |
1081 |
1082 |
1083 | Translate between an invocation and a list representation by using ‘equiv’ `=..`
1084 | as follows:
1085 |
1086 | ?- p(a, b, c) =.. Y. %⇒ Y = [p, a, b, c].
1087 | ?- Y =.. [p, a, b, c]. %⇒ Y = p(a, b, c).
1088 |
1089 |
1090 |
1091 |
1092 |
1093 | # Meta-Programming
1094 |
1095 | Programs as data: Manipulating Prolog programs with other Prolog programs.
1096 |
1097 | `clause(X, Y`) succeeds when `X` is the signature of a relation in the knowledge base,
1098 | and `Y` is the body of one of its clauses. `X` must be provided in the form `f(X₁, …, Xₙ)`.
1099 |
1100 | test(you, me, us).
1101 | test(A, B, C) :- [A, B, C] = [the, second, clause].
1102 |
1103 | % ?- clause(test(Arg1, Arg2, Arg3), Body).
1104 | % ⇒ ‘Body’ as well as ‘Arg𝒾’ are unified for each clause of ‘test’.
1105 |
1106 | Here is a Prolog interpreter in Prolog —an approximation to `call`.
1107 |
1108 | % interpret(G) succeeds as a goal exactly when G succeeds as a goal.
1109 |
1110 | % Goals is already true.
1111 | interpret(true) :- !.
1112 |
1113 | % A pair of goals.
1114 | interpret((G, H)) :- !, interpret(G), interpret(H).
1115 |
1116 | % Simple goals: Find a clause whose head matches the goal
1117 | % and interpret its subgoals.
1118 | interpret(Goal) :- clause(Goal,Subgoals), interpret(Subgoals).
1119 |
1120 | % ?- interpret(test(A, B, C)).
1121 |
1122 | Challenge: There are many shortcomings with this interpreter, such as no support for interpreting
1123 | recursive functions, negation, failures, and disjunctions. Fix it!
1124 |
1125 |
1126 |
1127 |
1128 | ## `Print, var, nonvar, arg`
1129 |
1130 | The `print` predicate always succeeds, never binds any variables, and prints out its
1131 | parameter as a side effect.
1132 |
1133 | Use built-ins `var` and `nonvar` to check if a variable is free or bound.
1134 |
1135 | ?- var(Y). %⇒ true
1136 | ?- Y = 2, var(Y). %⇒ false
1137 | ?- Y = 2, nonvar(Y). %⇒ true
1138 |
1139 | Built-in `arg(N,T,A`) succeeds if `A` is the `N`-th argument of the term `T`.
1140 |
1141 | % ?- arg(2, foo(x, y), y). %⇒ true
1142 |
1143 |
1144 |
1145 |
1146 | # Reads
1147 |
1148 | - [X] [Introduction to logic programming with Prolog](https://www.matchilling.com/introduction-to-logic-programming-with-prolog/) —12 minute read.
1149 | - [X] [Introduction to Prolog](http://www.doc.gold.ac.uk/~mas02gw/prolog_tutorial/prologpages/index.html#menu) —with interactive quizzes
1150 | - [ ] [Derek Banas' Prolog Tutorial](https://www.youtube.com/watch?v=SykxWpFwMGs) —1 hour video
1151 | - [X] [A Practo-Theoretical Introduction to Logic Programming](https://blog.algorexhealth.com/2018/11/a-practo-theoretical-introduction-to-logic-programming/) —a **colourful** read showing Prolog ≈ SQL.
1152 | - [ ] [Prolog Wikibook](https://en.wikibooks.org/wiki/Prolog) —slow-paced and cute
1153 | - [ ] [James Power's Prolog Tutorials](http://www.cs.nuim.ie/~jpower/Courses/Previous/PROLOG/)
1154 | - [X] [Introduction to Logic Programming Course](https://www3.risc.jku.at/education/courses/ws2009/logic-programming/) —Nice slides
1155 | - [ ] [Stackoverflow Prolog Questions](https://stackoverflow.com/questions/tagged/prolog) —nifty FAQ stuff
1156 | - [ ] [99 Prolog Problems](https://sites.google.com/site/prologsite/prolog-problems) —with solutions
1157 | - [ ] [The Power of Prolog](https://www.metalevel.at/prolog) –up to date tutorial, uses libraries ;-)
1158 | - [ ] [Backtracking](https://www.cis.upenn.edu/~matuszek/cit594-2012/Pages/backtracking.html)
1159 | - [ ] [Escape from Zurg: An Exercise in Logic Programming](http://web.engr.oregonstate.edu/~erwig/papers/Zurg_JFP04.pdf)
1160 | - [ ] [Efficient Prolog](https://www3.risc.jku.at/education/courses/ws2009/logic-programming/additional/Covington-Efficient-Prolog.pdf) –Practical tips
1161 | - [ ] [Use of Prolog for developing a new programming language](https://pdfs.semanticscholar.org/57d3/1ca47fa9688089b9b7e7c19c199aa03aff1e.pdf) —Erlang!
1162 | - [ ] [prolog :- tutorial](https://www.cpp.edu/~jrfisher/www/prolog_tutorial/pt_framer.html) —Example oriented
1163 | - [ ] [Learn Prolog Now!](http://www.learnprolognow.org/) (or [here](http://cs.union.edu/~striegnk/learn-prolog-now/html/index.html)) —thorough, from basics to advanced
1164 | - [ ] [Real World Programming in SWI-Prolog](http://www.pathwayslms.com/swipltuts/index.html)
1165 | - [ ] [Adventures in Prolog](https://www.amzi.com/AdventureInProlog/a1start.php) —Amzi! inc.
1166 |
1167 |
1168 |
1169 |
1170 |
1171 |
1172 |
1173 |
1174 |
1175 | | Also, here's [a nice set of 552 slides](https://people.eng.unimelb.edu.au/adrianrp/COMP90054/lectures/Prolog_Coding.pdf) ^\_^ |
1176 |
1177 |
1178 |
1179 |
--------------------------------------------------------------------------------
/CheatSheet.org:
--------------------------------------------------------------------------------
1 | # Reading here last:
2 | # http://cs.union.edu/~striegnk/learn-prolog-now/html/node34.html#sec.l4.member
3 | #
4 |
5 | # Makam is a dialect of λ-Prolog designed as a tool for rapid language prototyping. I won't go into details, but it's based on the idea of higher-order logic programming.
6 | #
7 | # https://www.tweag.io/posts/2019-11-28-pcf-makam-spec
8 |
9 | # The Prolog Dictionary
10 | # http://www.cse.unsw.edu.au/~billw/prologdict.html
11 |
12 | # Solving a logic puzzle using Prolog
13 | # https://stackoverflow.com/questions/1939054/solving-a-logic-puzzle-using-prolog
14 |
15 | # Logic Puzzles with Prolog
16 | # https://www.metalevel.at/prolog/puzzles
17 |
18 | :More:
19 | % types
20 | p(1). p(2). p(3).
21 | q(2). q(3).
22 |
23 | % intersection.
24 | int(X) :- p(X), q(X).
25 |
26 | % no solns
27 | empty(X) :- p(X),!, q(X).
28 |
29 | % product type
30 | prod(X, Y) :- p(X), q(Y).
31 |
32 | % section / currying
33 | cur(X, Y) :- p(X), !, q(Y).
34 |
35 | % first element in product tpye
36 | one(X, Y) :- p(X), q(Y), !.
37 |
38 | % n ↦ Σ i : 0..n • i
39 | % n ↦ Σⁿᵢ₌₀ i
40 | upto_(0, 0).
41 | upto_(N, Tot) :-
42 | M is N - 1,
43 | upto_(M, TotM),
44 | Tot is TotM + N.
45 | /*
46 | Σⁿᵢ₌₀ i ≈ n + Σⁿ⁻¹ᵢ₌₀ i
47 | upto n ≈ n + upto (n-1)
48 | */
49 |
50 | % PROBLEM:
51 | % If we press “;” for query
52 | % upto_(5, Tot)
53 | % we get an attempt to find
54 | % multiple solutions
55 | % and non-termination.
56 |
57 | % cut out choice of clauses
58 | % when base case is encountered.
59 | upto(0, 0) :- !.
60 | upto(N, Tot) :-
61 | M is N - 1,
62 | upto(M, TotM),
63 | Tot is TotM + N.
64 |
65 | :End:
66 |
67 | #+TITLE: Prolog CheatSheet
68 | # +SUBTITLE: ---Reference Sheet for “What I'm Currently Learning”---
69 | #+MACRO: blurb Refernece card for getting started with Prolog.
70 | #+AUTHOR: [[http://www.cas.mcmaster.ca/~alhassm/][Musa Al-hassy]]
71 | #+EMAIL: alhassy@gmail.com
72 | #+INCLUDE: CheatSheetSetup.org
73 | #+PROPERTY: header-args :tangle "CheatSheet.pl" :comments link
74 | #+TODO: Todo | spacing LaTeX
75 |
76 | * LaTeX Extra, Local, Setup :ignore:
77 |
78 | #+HTML_HEAD:
79 |
80 | # Empty by default.
81 | #+MACRO: url https://github.com/alhassy/PrologCheatSheet
82 | #+LATEX_HEADER: \def\cheatsheeturl{https://github.com/alhassy/PrologCheatSheet}
83 |
84 | # The following are the defaults & may be omitted.
85 | #+LATEX_HEADER: \def\cheatsheetcols{2}
86 | #+LATEX_HEADER: \landscapetrue
87 | #+LATEX_HEADER: \def\cheatsheetitemsep{-0.5em}
88 |
89 | # Example unicode declarations; see section “unicode” below.
90 | #+LATEX_HEADER: \newunicodechar{𝑻}{\ensuremath{T}}
91 | #+LATEX_HEADER: \newunicodechar{⊕}{\ensuremath{\oplus}}
92 | #+LATEX_HEADER: \newunicodechar{≈}{\ensuremath{\approx}}
93 |
94 | #+LATEX_HEADER: \newunicodechar{ℰ}{\ensuremath{\mathcal{E}}}
95 | #+LATEX_HEADER: \newunicodechar{𝓍}{\ensuremath{\mathit{x}}}
96 | #+LATEX_HEADER: \newunicodechar{𝓅}{\ensuremath{\mathit{p}}}
97 | #+LATEX_HEADER: \newunicodechar{𝓇}{\ensuremath{\mathit{r}}}
98 |
99 | * COMMENT Homemade Interactive Prolog Setup
100 |
101 | In Prolog, one declares a relationship ~r(x0, x1, …, xn)~ to be true for the declared
102 | ~xi~ ---with a change of perspective any of the ~xi~ can be considered ‘input’ and the
103 | rest considered ‘output’.
104 |
105 | #+BEGIN_SRC emacs-lisp :tangle no
106 | (use-package prolog)
107 |
108 | ;; Obtain “swipl” interpreter.
109 | (async-shell-command "brew install swi-prolog")
110 |
111 | ;; alhassy-air:~ musa$ swipl --version
112 | ;; SWI-Prolog version 8.0.2 for x86_64-darwin
113 | #+END_SRC
114 |
115 | The following did not work for me :'( ---so I made my own lolz.
116 | #+BEGIN_SRC emacs-lisp :tangle no
117 | (use-package ob-prolog)
118 | (org-babel-do-load-languages
119 | 'org-babel-load-languages
120 | '((prolog . t)))
121 |
122 | (use-package ediprolog)
123 | #+END_SRC
124 |
125 | Here's my current setup:
126 | #+BEGIN_SRC emacs-lisp :tangle no
127 | (local-set-key (kbd "") (lambda () (interactive)
128 | "org-babel-tangle the whole file, then execute the final query
129 | in the current, or next-most, SRC block."
130 | (let (kill-buffer-query-functions
131 | (inhibit-read-only t)
132 | (pl-file (car (org-babel-tangle))))
133 |
134 | ;; Kill *Prolog* buffer
135 | (ignore-errors
136 | (switch-to-buffer "*Prolog*")
137 | (kill-buffer "*Prolog*"))
138 |
139 | ;; Get final query in current source block
140 | (search-forward "#+END_SRC")
141 | (search-backward "% ?-")
142 |
143 | ;; Copy line, without killing it.
144 | (setq xx (thing-at-point 'line t))
145 |
146 | ;; Open the terminal, tangling & loading all Prolog code
147 | (split-window) (other-window 1)
148 | (ansi-term "swipl" "Prolog")
149 | (term-send-raw-string (format "consult('%s').\n" pl-file)))
150 |
151 | ;; Send the final query, i.e., “paste it and press enter at prompt”.
152 | (setq xx (s-chop-prefix "% ?- " xx))
153 | (term-send-raw-string (format "%s\n" xx))))
154 | #+END_SRC
155 |
156 | #+RESULTS:
157 | | lambda | nil | (interactive) | org-babel-tangle the whole file, then execute the final query |
158 |
159 | (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
160 |
161 | #+RESULTS:
162 | | lambda | nil | (interactive) |
163 |
164 | :Old_EShell:
165 | #+BEGIN_SRC emacs-lisp :tangle no
166 | (local-set-key (kbd "") (lambda () (interactive)
167 | "
168 | org-babel-tangle the whole file, then execute the final query
169 | in the current SRC block.
170 |
171 | If the query mentions the variable ‘X’, then show all possible solutions
172 | followed by ‘false’. Usually one presses ‘;’ to see other solutions,
173 | but in Emacs this only shows one futher solution then terminates.
174 | We get around this by executing essentially
175 | “forall(your-query-with-X, writeln(X)).”
176 | This prints all solutions X to your query.
177 |
178 | If you want to use a variable but don't want to see all solutions,
179 | then avoid using ‘X’; e.g., use ‘Y’ ^_^.
180 | "
181 | (-let [kill-buffer-query-functions nil]
182 | (ignore-errors
183 | (switch-to-buffer "*Prolog*")
184 | (kill-buffer "*Prolog*"))
185 |
186 | ;; Get final query in current source block
187 | (search-forward "#+END_SRC")
188 | (search-backward "% ?-")
189 | ;; Copy line, without killing it.
190 | (setq xx (thing-at-point 'line t))
191 |
192 | (async-shell-command (format "swipl -s %s" (car (org-babel-tangle))) "*Prolog*")
193 | (other-window 1)
194 |
195 | ;; Paste the final query
196 | (setq xx (s-chop-prefix "% ?- " xx))
197 | (when (s-contains? "X" xx)
198 | (setq xx (concat "writeln(\"X =\"), forall(" (s-replace "." ", writeln(X))." xx))))
199 |
200 | (insert xx)
201 | (comint-send-input nil t) ;; Send it, i.e., “press enter at prompt”.
202 |
203 | ;; Insert query again, but do not send, in case user wishes to change it.
204 | (insert xx)
205 | (previous-line) (end-of-line)
206 |
207 | )))
208 | #+END_SRC
209 | :End:
210 |
211 | #+RESULTS:
212 | | lambda | nil | (interactive) |
213 |
214 | For example:
215 | #+BEGIN_SRC prolog
216 | magicNumber(7).
217 | magicNumber(9).
218 | magicNumber(42).
219 |
220 | % ?- magicNumber(8).
221 | % ?- magicNumber(X).
222 | #+END_SRC
223 |
224 | Press ~f6~ to obtain all solutions ~X~ to this query :grin:
225 |
226 | Or
227 | #+BEGIN_SRC prolog
228 | main :- write('Hello, world!').
229 |
230 | % ?- main.
231 | #+END_SRC
232 |
233 | This little setup has made exploring Prolog fun for me; hopefully it will make
234 | Prolog fun for others 😄
235 |
236 | :TODOS:
237 | ToDo: Get the query, replace (,) with space, split to words, filter those
238 | that start with a capital letter, these are the variables. Execute:
239 | forall( (query) , ( write("Var0 = "), write(Var0), write(" "), write("Var1 = "), … ) ))
240 | :END:
241 |
242 | * Administrivia
243 | /Everything is a relation!/ ---I.e., a table in a database!
244 |
245 | #+latex: \vspace{1em}
246 | Whence programs are [[https://blog.algorexhealth.com/2018/11/a-practo-theoretical-introduction-to-logic-programming/][unidirectional]] and can be ‘run in reverse’:
247 | Input arguments and output arguments are the same
248 | thing! Only perspective shifts matter.
249 |
250 | #+latex: \vspace{1em}
251 | For example, defining a relation ~append(XS, YS, ZS)~
252 | /intended/ to be true precisely when ~ZS~ is the catenation of ~XS~ with ~YS~,
253 | gives us three other methods besides being a predicate itself!
254 | List construction: ~append([1, 2], [3, 4], ZS)~ ensures ~ZS~ is the catenation list.
255 | List subtraction: ~append([1,2], YS, [1, 2, 3, 4])~ yields all solutions ~YS~ to
256 | the problem ~[1, 2] ++ YS = [1, 2, 3, 4]~.
257 | Partitions: ~append(XS, YS, [1, 2, 3, 4])~ yields all pairs of lists that catenate
258 | to ~[1,2, 3, 4]~. *Four methods for the price of one!*
259 |
260 | #+latex: \vspace{1em}
261 | | Prolog is PROgramming in LOGic. |
262 |
263 | #+latex: \vspace{0.5em}
264 | In Prolog, the task of the programmer is simply to /describe/ problems
265 | ---write down, logically, the situation--- rather than telling the computer
266 | what to do, then obtains information by asking questions
267 | ---the logic programming system /figures out how/ to get the answer.
268 |
269 | - Prolog is declarative: A program is a collection of ‘axioms’ from which ‘theorems’
270 | can be proven. For example, consider how sorting is performed:
271 |
272 | + Procedurally: Find the minimum in the remainder of the list, swap it with the head
273 | of the list; repeat on the tail of the list.
274 |
275 | + Declaratively: ~B~ is the sorting of ~A~ /provided/ it is a permutation of ~A~ and it is
276 | ordered.
277 |
278 | Whence, a program is a theory and computation is deduction!
279 |
280 | #+latex: \vspace{1em}
281 | + ~swipl -s myprogram.pl~ --Load your program into a REPL, ~?-….~
282 | + ~make.~ --Reload your program.
283 | + ~halt.~ --Exit the REPL.
284 | + ~consult('CheatSheet.pl').~ --Load the contents of the given file as
285 | the new knowledge base.
286 | + ~assert((⋯)).~ --Add a new rule to the knowledge base, from within the REPL.
287 | Use ~retract((⋯))~ to remove rules from the knowledge base.
288 | - ~assert~ is useful when we want to [[http://cs.union.edu/~striegnk/learn-prolog-now/html/node94.html#sec.l11.database.manip][cache]] computations.
289 | + ~listing.~ --Display the contents of the current knowledge base; i.e.,
290 | what Prolog ‘knows’.
291 | + ~listing(name)~. --List all information in the knowledge base about
292 | the ~name~ predicate.
293 |
294 | * Syntax
295 |
296 | There are three types of terms:
297 | + Constants: Numbers such as -24, and atoms such as ~jasim~, ~'hello world'~,
298 | ~'&^%@$ &*',~ and ~' '~ ---a space in quotes.
299 | + Variables: Words starting with a capital letter or an underscore.
300 | - The variable ~_~ is called the /anonymous variable/.
301 |
302 | It's for when we need a variable, say when pattern matching,
303 | but don't care about the value.
304 |
305 | + Structures: Terms of the form ~functor(term₁,...,termₙ)~.
306 |
307 | ** ~name~ and ~atom_chars~
308 |
309 | The characters between single quotes are the /name/ of an atom
310 | and so Prolog admits ~symbol = 'symbol'~ as true.
311 |
312 | + Atoms, or nullary predicates, are represented as a lists of numbers; ASCII codes.
313 | + We can use this to compare two atoms lexicographically.
314 | + We can obtain the characters in an atom by using the built-in ~atom_chars~.
315 | #+BEGIN_SRC prolog :tangle no
316 | ?- name(woah, X). %⇒ X = [119,111,97,104]
317 | ?- atom_chars(nice, X). %⇒ X = [n, i, c, e].
318 | #+END_SRC
319 |
320 | * Facts & Relations
321 |
322 | We declare relations by having them begin with a lowercase letter;
323 | variables are distinguished by starting with a capital letter.
324 |
325 | #
326 | #+begin_parallel org
327 | #+BEGIN_SRC prolog
328 | /* Some facts of our world */
329 | jasim_is_nice.
330 | it_is_raining.
331 |
332 | % ?- jasim_is_nice.
333 | % ⇒ true: We declared it so.
334 | #+END_SRC
335 | #+latex: \columnbreak
336 | #+BEGIN_SRC prolog
337 | eats(fred, mangoes).
338 | eats(bob, apples).
339 | eats(fred, oranges).
340 |
341 | % Which foods are eaten by fred?
342 | % ?- eats(fred, what).
343 | %⇒ false; “what” is a name!
344 | % ?- eats(fred, What). %⇒ mangoes oranges
345 | #+END_SRC
346 | #+end_parallel
347 |
348 | Relational constraints are formed using ~:-~, which acts as the “provided”, ⇐,
349 | operator from logic. Read ~P :- Q~ as /P is true, provided Q is true./
350 | #
351 | #+begin_parallel org
352 | #+BEGIN_SRC prolog
353 | % All men are mortal.
354 | mortal(X) :- man(X).
355 |
356 | % Socrates is a man.
357 | man(socrates).
358 |
359 | % Hence, he's expected to be mortal.
360 | % ?- mortal(socrates). %⇒ true
361 | #+END_SRC
362 | #+latex: \columnbreak
363 | #+BEGIN_SRC prolog
364 | % What about Plato?
365 | ?- mortal(plato).
366 | %⇒ false, plato's not a man.
367 |
368 | % Let's fix that … in the REPL!
369 | ?- assert((man(plato))).
370 |
371 | % Who is mortal?
372 | ?- mortal(X). % ⇒ socrates plato
373 | #+END_SRC
374 | #+end_parallel
375 |
376 | * [[http://cs.union.edu/~striegnk/learn-prolog-now/html/node84.html#subsec.l9.operators.def][Mixfix Syntax]]
377 |
378 | #
379 | #+begin_parallel org
380 | It may feel awkward to write ~father_of(homer, bart)~ and instead prefer
381 | ~homer father_of bart~. We may declare relations to be prefix, infix, or postfix
382 | with patterns ~xf~, ~xfx~, and ~fx~ respectively. For left associativity
383 | we use pattern ~yfx~ and use ~xfy~ for right associativity.
384 | #+latex: \columnbreak
385 | #+BEGIN_SRC prolog
386 | :- op(35,xfx,father_of).
387 |
388 | father_of(me, you).
389 | homer father_of bart.
390 | homer father_of lisa.
391 | #+END_SRC
392 | #+end_parallel
393 |
394 | + Precedence, or binding power, is lowest at 1200 and highest at 0.
395 | + Note: ~father_of(X,Y) = X father_of Y~ is true.
396 |
397 | We may learn about existing operators too;
398 | #+latex: \newline
399 | e.g., ~?- current_op(Prec, Fixity, =:=)~ ^_^
400 |
401 | ** COMMENT Larger madlibs example
402 | As a larger example, we want to parse ~He ate It in ThePlace and was Emotive.~
403 | as if it were ~He ate (It in (ThePlace and (was Emotive.)))~ So we make the following
404 | declarations.
405 | #+BEGIN_SRC prolog
406 | % madlibs program
407 | :- op(35,xfx,ate).
408 | :- op(34,xfx,in).
409 | :- op(33,xfx,and).
410 | :- op(32,fx,was). % prefix
411 |
412 | noun(the_mayor).
413 | noun(jerry_the_duck).
414 | noun(a_microphone).
415 | noun(the_bed).
416 | noun(the_pumpkin).
417 | emotion(elated).
418 |
419 | He ate It :- noun(He), noun(It), It \= He.
420 | Action in Place :- noun(Action), noun(Place).
421 | This and That.
422 | was Emotive :- emotion(Emotive).
423 |
424 | He ate It in ThePlace and was Emotive
425 | :- noun(He), noun(It), It \= He,
426 | noun(ThePlace), emotion(Emotive).
427 |
428 | % ?- Who ate jerry_the_duck in the_pumpkin and was elated.
429 | #+END_SRC
430 |
431 | Neato!
432 |
433 | * Trace & Backtracking
434 |
435 | We can see what Prolog does at each step of a computation by invoking
436 | ~trace~; we turn off this feature with ~notrace.~
437 |
438 | #+latex: \vspace{0.5em}
439 | | /This’ an excellent way to learn how Prolog proof search works! (Debugging!)/ |
440 |
441 | #
442 | #+begin_parallel org
443 | Suppose we have the following database.
444 | #+BEGIN_SRC prolog :tangle no
445 | q(1). q(2). q(3).
446 | r(2). r(3).
447 | p(X) :- q(X), r(X).
448 | #+END_SRC
449 | #+latex: \columnbreak
450 | With trace, query ~p(X)~ and press
451 | /SPACE/ each time to see what
452 | Prolog is doing.
453 | At one point, the goal ~r(1)~ will
454 | /fail/ and that choice $X = 1$
455 | will be redone with the next possibility
456 | for ~q~, namely $X = 2$.
457 | #+end_parallel
458 |
459 | The line marked ~redo~ is when Prolog realizes its taken the wrong
460 | path, and backtracks to instantiate the variable to 2.
461 |
462 | Operationally, query ~p(X)~ is answered by:
463 | 1. Find match for the first goal: ~q~ at ~1~.
464 | 2. Then see if matches the second: ~r~ at ~1~.
465 | 3. (Redo) If not, find another match for the first: ~q~ at ~2~.
466 | 4. See if this matches the second, ~r~.
467 | 5. Etc.
468 |
469 | #+latex: \vspace{2em}\hrule\vspace{1em}
470 |
471 | + ~findall(X, Goal, L)~ succeeds if ~L~ is the list of all those ~X~'s for
472 | which ~Goal~ holds.
473 |
474 | + ~fail/0~ immediately fails when encountered. Remember: Prolog tries to
475 | backtrack when its fails; whence ~fail~ can be viewed as an
476 | instruction to force backtracking.
477 |
478 | The opposite of forcing backtracking is to block it, which is done
479 | with ‘cut’ ~!~ ---see below.
480 |
481 | * What is a Prolog Program Exactly?
482 |
483 | A program /denotes/ all true facts derivable from its clauses using
484 | *modus ponens, unification, term rewriting, and logical or-&-and*
485 | for the execution model.
486 |
487 | Hidden Quantifiers:
488 | | _Syntax_ | _Semantics_ |
489 | | ~head(X) :- body(X,Y).~ | $∀ X.\, head(X) \,⇐\, ∃ Y.\, body(X,Y)$ |
490 | | ~?- Q(X)~ | $∃ X.\, Q(X)$ |
491 |
492 | 1. “ ~head(X)~ is true provided there's some ~Y~ such that ~body(X,Y)~ is true ”
493 | - ~head.~ is an abbreviation for ~head :- true.~
494 | - Indeed, $p \;≡\; (p ⇐ true)$.
495 | 2. “ Is there an ~X~ so that ~Q(X)~ is true? ”
496 |
497 | ** One point rule
498 | “One-Point Rule”: Provided ~X~ is a fresh variable,
499 | | ~f(⋯X⋯) :- X = ℰ𝓍𝓅𝓇.~ | ≈ | ~f(⋯ℰ𝓍𝓅𝓇⋯).~ |
500 |
501 | ** Overloading
502 |
503 | /Overloading!/ Predicates of different arities are considered different.
504 |
505 | | Documentation Convention: | ~f/N~ | ≈ | /relation ~f~ takes ~N~-many arguments/ |
506 |
507 | * Modus Ponens --- Computation ≈ Deduction
508 | The logical rule $p ∧ (p ⇒ q) \;⇒\; q$ says if we have $p$, and from
509 | that we know we can get a $q$, then we have a $q$. From the following program
510 | on the left, we get ~q(a)~ is true.
511 |
512 | #
513 | #+begin_parallel org
514 | #+BEGIN_SRC prolog :tangle no
515 | p(a).
516 | q(X) :- p(X).
517 | #+END_SRC
518 | #+latex: \columnbreak
519 | We /rewrite/ term ~X~ with atom ~a~ to obtain ~q(a) :- p(a)~ from the second rule,
520 | but we know ~p(a)~, and so we have /computed/ the new fact ~q(a)~ by using the
521 | deduction rule modus ponens.
522 | #+end_parallel
523 |
524 | * Conjunction ≈ Constraints --- Disjunction ≈ Alternatives
525 |
526 | Conjunction: ~p(X), q(X)~ means “let ~X~ be /a/ solution to ~p~, then use it in query ~q~.”
527 |
528 | #
529 | #+begin_parallel org
530 | Operational semantics: Let ~X~ be the first solution declared, found,
531 | for ~p~, in the user's script, then try ~q~; if it fails, then /backtrack/
532 | and pick the next declared solution to ~p~, if any, and repeat until ~q~
533 | succeeds ---if possible, otherwise fail.
534 | #+latex: \columnbreak
535 | #+BEGIN_SRC prolog
536 | yum(pie).
537 | yum(apples).
538 | yum(maths).
539 |
540 | % ?- yum(Y), writeln(Y), fail.
541 | %⇒ pie apples maths false.
542 | #+END_SRC
543 | #+end_parallel
544 |
545 | “Fail driven loop” ~p(X), print(X), fail.~ gets a solution to ~p~, prints
546 | it, then fails thereby necessitating a backtrack to obtain a
547 | different solution ~X~ for ~p~, then repeats. In essence, this is prints
548 | all solutions to ~p~.
549 |
550 | “Let Clauses”: Provided ~X~ is a fresh variable,
551 | | ~⋯ℰ𝓍𝓅𝓇⋯ℰ𝓍𝓅𝓇⋯~ | ≈ | ~X = ℰ𝓍𝓅𝓇, ⋯X⋯X⋯~ |
552 |
553 | A Prolog program is the conjunction of all its clauses, alternatives ‘;’.
554 | #
555 | #+begin_parallel org
556 | #+BEGIN_SRC prolog :tangle no
557 | % (head ⇐ body₁) ∧ (head ⇐ body₂)
558 | head :- body₁.
559 | head :- body₂.
560 | ≈
561 | % head ⇐ body₁ ∨ body₂
562 | head :- body₁ ; body₂.
563 | #+END_SRC
564 | #+latex: \columnbreak
565 | Read ‘⇐’ as ‘≥’, and ‘∨’ as maximum, then the following is the
566 | “characterisation of least upper bounds”.
567 | #+latex: \vspace{0.5em}
568 |
569 | | | $(p ⇐ q) ∧ (p ⇐ r)$ |
570 | | ≡ | |
571 | | | $p ⇐ (q ∨ p)$ |
572 | #+end_parallel
573 |
574 | “And binds stronger than Or”: ~a,b;c ≈ (a,b);c~.
575 |
576 | * [[http://cs.union.edu/~striegnk/learn-prolog-now/html/node15.html][Unification]]
577 |
578 | A program can be written by having nested patterns, terms, then we use
579 | matching to pull out the information we want!
580 |
581 | Two terms /match/ or /unify/, if they are equal or if they contain variables that
582 | can be instantiated in such a way that the resulting terms are equal.
583 |
584 | #+latex: \vspace{1em}
585 | + Unification :: Can the given terms be made to represent the same structure?
586 | - This is how type inference is made to work in all languages.
587 |
588 | + Backtracking :: When a choice in unification causes it to fail, go back to the
589 | most recent choice point and select the next available choice.
590 |
591 | - Nullary built-in predicate ~fail~ always fails as a goal and causes backtracking.
592 |
593 | #+latex: \vspace{0.2em}
594 | ** Operational Semantics
595 | #
596 | #+begin_parallel org
597 | The unification predicate is ~=/2~. It can be written with the usual
598 | notation ~=(L, R)~ but can also be written infix ~L = R~.
599 | #+latex: \columnbreak
600 | #+BEGIN_SRC prolog
601 | % Query: Who is loved by Jay?
602 | ?- loves(jay, X) = loves(jay, kathy).
603 | % ⇒ X = kathy
604 | #+END_SRC
605 | #+end_parallel
606 |
607 | Operationally ~ℒ = ℛ~ behaves as follows:
608 | 1. If either is an unbound variable, assign it to the other one.
609 | - A constant unifies only with itself.
610 | - A variable unifies with anything.
611 | 2. Otherwise, they are both terms.
612 | - Suppose $ℒ ≈ f(e₁,…,eₙ)$ and $ℛ ≈ g(d₁,…,dₘ)$.
613 | - If ~f~ is different from ~g~, or ~n~ different from ~m~, then crash.
614 | - Recursively perform ~eᵢ = dᵢ~.
615 |
616 | Ensure the variable instantiations are compatible in that a
617 | variable is associated with at most one value ---which is
618 | not true in ~f(1,2) = f(X,X).~
619 |
620 | | *Thus variables are single ‘assignment’!* |
621 |
622 | Exception! Each occurrence of the anonymous variable ~_~
623 | is independent: Each is bound to something different.
624 |
625 | 3. If two terms can't be shown to match using the above clauses,
626 | then they don't match.
627 |
628 | | /Unification lets us solve equations!/ It lets us *compute!* |
629 |
630 | :Alternative_Explanation:
631 | 1. A constant unifies only with itself.
632 | 2. A variable unifies with anything.
633 | 3. Two structures unify precisely when they have
634 | the same head and the same number of arguments,
635 | and the corresponding arguments unify recursively,
636 | and the variable instantiations are compatible in that
637 | a variable is associated with at most one value
638 | ---which is not true in ~f(1,2) = f(X,X).~
639 | 4. If two terms can't be shown to match using Clauses 1-3, then they don't match.
640 | :End:
641 |
642 | #+latex: \vspace{1em}
643 | ** 'symbol' = symbol
644 |
645 | The query ~'symbol' = symbol~ is true since both are considered to be the same
646 | atom. Whereas ~'2' = 2~ is false since ~'2'~ is a symbolic atom but ~2~ is a number.
647 |
648 | The /discrepancy predicate/ ~\=/2~ succeeds when its arguments don't unify;
649 | e.g., ~'5' \= 5~ is true.
650 |
651 | #+latex: \vspace{1em}
652 | ** Unification performs no simplification, whence no arithmetic
653 |
654 | #
655 | #+begin_parallel org
656 | Unification performs no simplification, whence no arithmetic.
657 | This means, for example, we can form pairs by sticking an infix operator between two items; moreover we can form distinct kinds of pairs by using different operators.
658 | #+latex: \columnbreak
659 | #+BEGIN_SRC prolog :tangle no
660 | ?- C + "nice" = woah + Z.
661 | C = woah, Z = "nice".
662 |
663 | % ‘+’ and ‘/’ are different,
664 | % so no way to make these equal.
665 | ?- C + "nice" = woah / Z.
666 | false.
667 | #+END_SRC
668 | #+end_parallel
669 |
670 | ** COMMENT Informally, in pseudo-Prolog:
671 | #+BEGIN_SRC prolog :tangle no
672 | unify(X, Y) :- X = Y.
673 | unify(X, Y) :- nonvar(X), nonvar(Y), X = Y.
674 | unify(F(X0, …, XN), G(Y0, …, YN)) :- F = G, X_i = Y_i.
675 |
676 | % ?- unify(A, B). %⇒ true with A = B.
677 | % ?- unify(1, 2). %⇒ false.
678 |
679 | #+END_SRC
680 |
681 | * COMMENT ‘=’ is Unification, or ‘incremental tell’
682 |
683 | Here's another example; “wildcard” ~_~ is used to match anything
684 | ---so-called “anonymous variable”.
685 | #+BEGIN_SRC prolog
686 | declare Second L
687 | [a b c] = L
688 | L = [_ Second _]
689 | {Show Second} % ⇒ b
690 | #+END_SRC
691 |
692 | | Whence, pattern matching is unification! |
693 |
694 | Unification is the primary method of computation in [[https://github.com/alhassy/PrologCheatSheet][Prolog]].
695 | * Algebraic Datatypes
696 |
697 | Uniform treatment of all datatypes as predicates! Enumerations, pairs, recursives:
698 |
699 | #
700 | #+begin_parallel org
701 | _Haskell_
702 | #+BEGIN_SRC haskell :tangle no
703 | data Person = Me | You | Them
704 |
705 |
706 |
707 | data Pair a b = MkPair a b
708 |
709 | data Nat = Zero | Succ Nat
710 |
711 |
712 | sum Zero n = n
713 | sum (Succ m) n = Succ (sum m n)
714 | #+END_SRC
715 |
716 | #+latex: \columnbreak
717 |
718 | _Prolog_
719 | #+BEGIN_SRC prolog
720 | person(me).
721 | person(you).
722 | person(them).
723 |
724 | pair(_, _).
725 |
726 | nat(zero).
727 | nat(succ(N)) :- nat(N).
728 |
729 | sum(zero, N, N).
730 | sum(succ(M), N, succ(S))
731 | :- sum(M, N, S).
732 | #+END_SRC
733 | #+end_parallel
734 |
735 | #
736 | # % ?- pair(1, "nice").
737 | # % ?- pair(1, "nice") = pair(A, "nice"). %⇒ A = 1
738 | # % ?- nat(succ(succ(zero))).
739 | # % ?- Two = succ(succ(zero)), Four = succ(succ(succ(succ(zero)))), sum(Two, Two, Four).
740 |
741 | Exercise: Form binary trees.
742 | :Answer:
743 | _Binary Trees_ ---Recursive ADTs
744 | #+BEGIN_SRC prolog
745 | % In Haskell: Tree a = Leaf a | Branch (Tree a) (Tree a)
746 |
747 | tree(leaf(_)).
748 | tree(branch(L, R)) :- tree(L), tree(R).
749 |
750 | % ?- A = leaf(1), B = leaf(2), L = branch(A, B), R = branch(A, A), tree(branch(L, R)).
751 | #+END_SRC
752 | :end:
753 |
754 | * Arithmetic with ~is~ ---Using Modules
755 | Use ~is~ to perform arithmetic with ~+, -, *, /, **, mod~, and
756 | ~//~ for integer division.
757 | #+BEGIN_SRC prolog
758 | % How do we make this equation equal?
759 | ?- X = 3 + 2.
760 | % ⇒ X = 3 + 2; this choice of variables make its equal!
761 |
762 | % Everything is a term! Terms don't ‘compute’!
763 | ?- +(3, 2) = 3 + 2. % ⇒ true
764 | ?- +(3, 2) = 6 - 1. % ⇒ false
765 |
766 | #+END_SRC
767 | #
768 | #+begin_parallel org
769 | #+BEGIN_SRC prolog
770 | ?- X is 3 + 2. % ⇒ X = 5
771 | ?- 5 is 6 - 1. % ⇒ true
772 | ?- 5 is X. % ⇒ CRASH!
773 | ?- 3 + 2 is 6 - 1. %⇒ CRASH!
774 | #+END_SRC
775 | #+latex: \columnbreak
776 | #+BEGIN_SRC prolog
777 | ?- +(3, 2) =:= 6 - 1. % ⇒ true
778 | ?- 1 =:= sin(pi/2). % ⇒ true
779 | ?- X =:= 3 + 2. % ⇒ CRASH!
780 | ?- X = 2, Y = 3, X + Y =:= 5. % ⇒ true
781 | #+END_SRC
782 | #+end_parallel
783 |
784 | # + Unification only tries to make both sides of an equality true by binding free
785 | # variables to expressions. It does not do any arithmetic.
786 | #
787 | # Comparison operators: ~=, \=, <, >~, ~=<~, and ~>=~.
788 |
789 | + ~is~ takes a /variable, or a numeric constant,/ and an arithmetical
790 | expression as arguments.
791 | - ~L is R~ means “ unify ~L~ with the result of simplifying ~R~ ”
792 | - If ~R~ mentions an unbound variable, crash!
793 | + ~=:=~ has both arguments as /concrete terms/, it evaluates them and compares the results.
794 | | ~𝓁 =:= 𝓇~ | ≈ | ~L is 𝓁, R is 𝓇, L = R~. |
795 |
796 |
797 | # In the context of the CLP(B) library, ~=:=~ is Boolean equality.
798 | # TODO: Show some examples.
799 |
800 | ** Using Modules
801 |
802 | #
803 | #+begin_parallel org
804 |
805 | The [[http://www.swi-prolog.org/pldoc/man?section=clpfd][Constraint Logic Programming over Finite Domains]] library provides a number of
806 | useful functions, such as ~all_distinct~ for checking a list has unique elements.
807 |
808 | See [[http://www.swi-prolog.org/pldoc/man?section=clpfd-sudoku][here]] for a terse solution to Sudoku.
809 |
810 |
811 | In particular, ~=:=~ is too low level ---e.g., it doesn't admit unbound variables---
812 | instead one uses ~clpfd~'s ~#=/2~ predicate.
813 |
814 | Likewise we could use ~in~ to check if a number is in a particular range, or instead use ~#>/2~ and ~#2~.
815 |
816 | #+latex: \columnbreak
817 | #+BEGIN_SRC prolog
818 | use_module(library(clpfd)).
819 |
820 | ?- all_distinct([1,"two", two]).
821 |
822 | ?- X + 2 #= 3. %⇒ X = 1
823 | ?- 1 + Y #= 3. %⇒ Y = 2.
824 | ?- X #= Y. %⇒ Also works ;-)
825 |
826 | ?- 2 in 0..3. %⇒ true.
827 | ?- 3 #> X, 0 #< X. %⇒ X in 1..2.
828 |
829 | % All parititions of number N ^_^
830 | ?- N = 5, between(0, N, X),
831 | between(0, N, Y), X + Y #= N.
832 | #+END_SRC
833 | #+end_parallel
834 |
835 | * Lists
836 |
837 | Lists are enclosed in brackets, separated by commas, and can be split
838 | up at any point by using cons “|”. The empty list is ~[]~.
839 | #+BEGIN_SRC prolog
840 | ?- ["one", two, 3] = [Head|Tail].
841 | %⇒ Head = "one", Tail = [two, 3].
842 |
843 | ?- ["one", two, 3] = [_,Second|_].
844 | %⇒ Second = two.
845 |
846 | ?- [[the, Y], Z] = [[X, hare], [is, here]].
847 | %⇒ X = the, Y = hare, Z = [is, here]
848 | #+END_SRC
849 |
850 | Searching: $x ∈ l$?
851 | #+BEGIN_SRC prolog
852 | elem(Item, [Item|Tail]). % Yes, it's at the front.
853 | elem(Item, [_|Tail]) :- elem(Item, Tail). % Yes, it's in the tail.
854 |
855 | % ?- elem(one, [this, "is", one, thing]). %⇒ true
856 | % ?- elem(onE, [this, "is", one, thing]). %⇒ false
857 | #+END_SRC
858 |
859 | See [[http://www.swi-prolog.org/pldoc/man?section=lists][here]] for the list library, which includes:
860 | #
861 | #+begin_parallel org
862 | #+BEGIN_SRC prolog :tangle no
863 | member(element, list)
864 | append(list1, list2, lists12)
865 | prefix(part, whole)
866 | nth0(index, list, element)
867 | last(list, element)
868 | length(list, number)
869 | reverse(list1, list2)
870 | permutation(list1, list2)
871 | sum_list(list, number)
872 | max_list(list, number)
873 | is_set(list_maybe_no_duplicates)
874 | #+END_SRC
875 | #+latex: \columnbreak
876 | In Haskell, we may write ~x:xs~, but trying that here forces us to write
877 | ~[X|XS]~ or ~[X|Xs]~ and accidentally mismatching the capitalisation of the ‘s’
878 | does not cause a compile-time error but will yield an unexpected logical error
879 | --e.g., in the recursive clause use ~Taill~ instead of ~Tail~.
880 | As such, prefer the ~[Head|Tail]~ or ~[H|T]~ naming.
881 | #+end_parallel
882 | Exercise: Implement these functions.
883 | :MySolutions:
884 | #+BEGIN_SRC prolog
885 | % member is above, ‘elem’.
886 |
887 | append([], List2, List2).
888 | append([H|T], List2, [H|Append]) :- append(T, List2, Append).
889 |
890 | % ?- append([1,"two", three], [four, "5", "6"], Result).
891 |
892 | prefix([], List).
893 | prefix([H|T], [H|List]) :- prefix(T, List).
894 |
895 | % ?- prefix([1,2,three], [1, 2, three, four]).
896 | % ?- not(prefix([1,2,three], [1, 2])).
897 |
898 | nth0(0, [H|T], H).
899 | nth0(X, [_|T], E) :- Y is X - 1, nth0(Y, T, E).
900 |
901 | % ?- nth0(2, [one, two, three], X).
902 | % ?- not(nth0(2, [one, two], X)).
903 |
904 | last([H],H).
905 | last([_|T], L) :- last(T, L).
906 |
907 | % ?- last([1,2,3], L).
908 | % ?- last([1,2], L).
909 | % ?- not(last([], L)).
910 |
911 | mylength([], 0).
912 | mylength([H|T], Res) :- length(T, L), Res is L + 1.
913 |
914 | % ?- mylength([1,2,3], L).
915 |
916 | % count(E, L, N) ≡ E occurs N times in L
917 | count(E, [], 0).
918 | count(E, [E|T], Res) :- count(E, T, N), Res is N + 1.
919 | count(E, [_|T], N) :- count(E, T, N).
920 |
921 | % ?- count(2, [1,2,1,3,2], N).
922 |
923 | % For each element x of list1, let n1 and n2 be the number of times x occurs in list1 and list2; they're bag-equal if n1 = n2. Note: elem requires a non-empty list.
924 | #+END_SRC
925 | :End:
926 |
927 | Hint: Arithmetic must be performed using ~is~.
928 |
929 | ** COMMENT Lists as user-defined ADT
930 | Programming via specification: Lisp lists, for example, are defined by the following
931 | equations.
932 | #+BEGIN_SRC prolog
933 | % Head: (car (cons X Xs)) = X
934 | % Tail: (cdr (cons X Xs)) = Xs
935 | % Extensionality: (cons (car Xs) (cdr Xs)) = Xs, for non-null Xs.
936 |
937 | % We can just write the spec up to produce the datatype!
938 | % We simply transform /functions/ car and cdr into relations;
939 | % leaving the constructor, cons, alone.
940 |
941 | % What are lists?
942 | list(nil).
943 | list(cons(_, Xs)) :- list(Xs).
944 |
945 | null(nil).
946 |
947 | car(cons(X, Xs), X) :- list(Xs).
948 | cdr(cons(_, Xs), Xs) :- list(Xs).
949 |
950 | % ?- true.
951 | % - list(Ys), not(null(L)), list(cons(car(Ys, Y), cdr(Ys, L))). % loops.
952 |
953 | % ?- [1] = [1|[]].
954 | #+END_SRC
955 |
956 | * Declaration Ordering Matters ---Recursion
957 |
958 | Prolog searches the knowledge base from top to bottom, clauses from
959 | left to right, and uses backtracking to recover from bad choices.
960 |
961 | When forming a recursive relation, ensure the base case, the
962 | terminating portion, is declared before any portions that require
963 | recursion. Otherwise the program may loop forever.
964 |
965 | # +latex: \vspace{1em}
966 | Unification is performed using depth-first search using the order of
967 | the declared relationships. For example, the following works:
968 |
969 | #+BEGIN_SRC prolog
970 | % Acyclic graph: a ⟶ b ⟶ c ⟶ d
971 | edge(a, b). edge(b ,c). edge(c, d).
972 |
973 | % Works
974 | path(X, X).
975 | path(X, Y) :- edge(Z, Y) % Can we get to Y from some intermediary Z?
976 | , path(X, Z). % Can we get to the intermediary Z from X?
977 | % ?- path(a, d). %⇒ true.
978 |
979 | % Fails: To find a path, we have to find a path, before an edge!
980 | % The recursive clause is first and so considerd before the base clause!
981 | path_(X, Y) :- path_(X, Z), edge(Z, Y).
982 | path_(X, X).
983 | % ?- path_(a, d). %⇒ loops forever!
984 | #+END_SRC
985 |
986 | * The Cut
987 |
988 | Automatic backtracking is great, but can be a waste of time exploring
989 | possibilities that lead nowhere. The atom /cut/, ~!~, offers a way to
990 | control how Prolog looks for solutions:
991 | It always succeeds with a side-effect of committing to any choices made thus far
992 | ---including variable instantiations *and* rule, clause, chosen---
993 | whence ignoring any other possible branches and no backtracking!
994 |
995 | ~q :- p₁, …, pₙ, !, r₁, …, rₘ~
996 | ⇒ Once we reach the cut, we're commited to the choices made when evaluating the ~pᵢ~,
997 | but we are free to backtrack among the ~rᵢ~ *and* we may backtrack among the alternatives
998 | for choices that were made before reaching goal ~q~. Here's an example.
999 | #
1000 | #+ATTR_LATEX: :options [3]
1001 | #+begin_parallel org
1002 | #+BEGIN_SRC prolog
1003 | i(1). i(2).
1004 | j(1). j(2). j(3).
1005 | #+END_SRC
1006 | #+latex: \columnbreak
1007 | #+BEGIN_SRC prolog
1008 | k(X, Y) :- i(X), !, j(Y).
1009 | #+END_SRC
1010 | #+latex: \columnbreak
1011 | #+BEGIN_SRC prolog
1012 | l(X,Y) :- k(X,Y).
1013 | l(0,0).
1014 | #+END_SRC
1015 | #+end_parallel
1016 |
1017 | Query ~l(X, Y)~ yields
1018 | solutions 1-1, 1-2, 1-3, and 0-0.
1019 | Notice that ~X = 0, Y = 0~ is not
1020 | truthified by by the first clause of ~l~
1021 | but the choice of clause happened before the ~k~-clause
1022 | containing the cut ~!~ and so backtracking may pick another ~l~-clause.
1023 | Notice that without the cut, we have the extra solutions 2-1, 2-2, 2-3
1024 | which are “cut out” by ~!~ since ~i(1)~ is the choice we committed to for ~X = 1~
1025 | and we can backtrack for ~Y~ only since it comes after the cut.
1026 |
1027 | Suppose ~x₁~ is the first solution found for ~p~, then:
1028 | | ~p(X), q(Y)~ | ≈ | $\{ (x, y) ❙ p\, x \,∧\, q\, y\}$ |
1029 | | ~p(X), !, q(Y)~ | ≈ | $\{ (x₁, y) ❙ q\, y\}$ |
1030 |
1031 | ** Examples
1032 |
1033 | :Random_rambling:
1034 | Example ~a~: The first solution to ~b~ is 1, and when the cut is encountered, no
1035 | other solutions for ~b~ are even considered. After a solution for ~Y~ is found, backtracking
1036 | occurs to find other solutions for ~Y~.
1037 | #+BEGIN_SRC prolog
1038 | a(X,Y) :- b(X), !, c(Y).
1039 | b(1). b(2). b(3).
1040 | c(1). c(2). c(3).
1041 |
1042 | % ?- a(X, Y). %⇒ X = 1 ∧ Y = 1, X = 1 ∧ Y = 2, X = 1 ∧ Y = 3
1043 | #+END_SRC
1044 | # ?- writeln("X ="), forall(a(X, Y), (write(X), writeln(Y))).
1045 |
1046 | Below the first solution found for ~e~ is 1, this is not a solution for ~f~,
1047 | but backtracking cannot assign other values to ~X~ since ~X~'s value was determined
1048 | already as 1 and this is the only allowed value due to the cut. But ~f(1)~ is not
1049 | true and so ~d~ has no solutions. In contrast, ~d_no_cut~ is just the intersection.
1050 | #+BEGIN_SRC prolog
1051 | d(X) :- e(X), !, f(X).
1052 | e(1). e(2). e(3). f(2).
1053 |
1054 | % ?- not(d(X)). %⇒ “no solution” since only e(1) considered.
1055 | % ?- d(2). %⇒ true, since no searching performed and 2 ∈ e ∩ f.
1056 |
1057 | d_no_cut(X) :- e(X), f(X).
1058 | % ?- d_no_cut(X). %⇒ X = 2.
1059 | #+END_SRC
1060 | :End:
1061 |
1062 | Remember, the cut not only commits to the instantiations so far, but
1063 | also commits to the clause of the goal in which it occurs, whence no
1064 | other clauses are even tried!
1065 | #+BEGIN_SRC prolog :tangle no
1066 | g(X) :- h(X), !, i(X).
1067 | g(X) :- j(X).
1068 |
1069 | h(1). h(4). i(3). j(2).
1070 |
1071 | % ?- g(X). %⇒ fails
1072 | #+END_SRC
1073 | There are two clauses to prove ~g~, by default we pick the first one.
1074 | Now we have the subgoal ~h~, for which there are two clauses and we select
1075 | the first by default to obtain ~X = 1~. We now encounter the cut which means
1076 | we have committed to the current value of ~X~ and the current clause to prove ~g~.
1077 | The final subgoal is ~i(1)~ which is false. Backtracking does not allow us to select
1078 | different goals, and it does not allow us to use the second clause to prove ~g~.
1079 | Whence, ~g(X)~ fails. Likewise we fail for ~g(4)~. Note that if we had failed ~h~
1080 | before the cut, as is the case with ~g(2)~, then we fail that clause before encountering
1081 | the cut and so the second rule is tried.
1082 |
1083 | ** Disjoint Clauses
1084 |
1085 | When there are disjoint clauses, i.e., only one succeeds, then if
1086 | backtracking is forced at some point, trying other cases is a waste
1087 | of time since only one clause, say the first one, succeeds. An
1088 | example of this would be the maximum function or the $\sum_{i=0}^n i$ function.
1089 |
1090 | #
1091 | #+begin_parallel
1092 | #+BEGIN_SRC prolog
1093 | max_(X, Y, Y) :- X =< Y.
1094 | max_(X, Y, X) :- X > Y.
1095 |
1096 | % ?- trace.
1097 | % ?- max_(3, 4, Y).
1098 | % ⇒ Wastes time trying both clauses.
1099 |
1100 | max(X, Y, Y) :- X =< Y, !.
1101 | max(X, Y, X) :- X > Y.
1102 |
1103 | % ?- trace.
1104 | % ?- max(3, 4, Y).
1105 | % ⇒ Only first clause is tried ^_^
1106 | #+END_SRC
1107 | #+latex: \columnbreak
1108 | #+BEGIN_SRC prolog
1109 | sum_to(0, 0).
1110 | sum_to(N, Res) :- M is N - 1,
1111 | sum_to(M, ResM),
1112 | Res is ResM + N.
1113 |
1114 | % Example execution
1115 | % ?- sum_to(1, X).
1116 | % ⇒ Loops forever: Both clauses apply!
1117 |
1118 | % The fix is to mark the
1119 | % first clause as a “base case”.
1120 | sum_to(0, 0) :- !.
1121 | #+END_SRC
1122 | #+end_parallel
1123 |
1124 | The resulting code gives the /same/ results but is more /efficient/.
1125 | Such cuts are called /green cuts/. Changes to a program that /depend/
1126 | on a cut rather than the logic are called /red cuts/ and are best avoided
1127 | ---e.g., ~maxNo(X, Y, Y) :- X =< Y, !. maxNo(X, Y, X).~ works by relying on the cut:
1128 | It works with variables, but ~maxNo(2, 3, 2)~ matches the second clause unconditionally
1129 | even though 2 is not the maximum of 2 and 3!
1130 |
1131 | + Cut at the end ⇒ Don't consider any more clauses of the current predicate.
1132 | # + At the end, followed by ~fail~ ⇒ Like the above but also simply ~fail~.
1133 |
1134 | ** COMMENT Disjoint Clauses :possibly_better:
1135 | #+latex: \vspace{1em}
1136 | Common use: When disjoint clauses cannot be enforced by pattern matching.
1137 |
1138 | #+BEGIN_SRC prolog :tangle no
1139 | sum_to(0, 0).
1140 | sum_to(N, Res) :- M is N - 1, sum_to(M, ResM), Res is ResM + N.
1141 |
1142 | % Example execution
1143 | sum_to(1, X)
1144 | ⇒ M is 0 --only clause 2 applies
1145 |
1146 | Now both clauses apply.
1147 |
1148 | Clause1: ⇒ ResM = 0, Res = 0.
1149 | Clause2: ⇒ M′ is -1, sum_to(M′, ResM′), ⋯
1150 | ⇒ Clause 2 applies here, with M″ = -2.
1151 | ⇒ Loop forever.
1152 | #+END_SRC
1153 |
1154 | After we commit to the first clause, /cut/ out all other alternative clauses:
1155 | #+BEGIN_SRC prolog
1156 | sum_to(0, 0) :- !.
1157 | sum_to(N, Res) :- M is N - 1, sum_to(M, ResM), Res is ResM + N.
1158 |
1159 | % ?- sum_to(1, X).
1160 | #+END_SRC
1161 |
1162 | It may be clearer to replace cuts with negations so as to enforce disjoint clauses.
1163 | #+BEGIN_SRC prolog
1164 | sum_to_not(0, 0).
1165 | sum_to_not(N, Res) :- N \= 0, M is N - 1, sum_to(M, ResM), Res is ResM + N.
1166 |
1167 | % ?- sum_to_not(5, X). %⇒ X = 15.
1168 | #+END_SRC
1169 |
1170 | In general, ~not(G)~ succeeds when /goal/ ~G~ fails.
1171 |
1172 | ** Conditional
1173 | *Lazy Conditional*
1174 | | ~A -> B; C~ | If ~A~ is true, then prove ~B~ and ignore ~C~; else prove ~C~ and ignore ~B~. |
1175 |
1176 | + The “; C” portion is /optional/ and ~C~ defaults to ~fail~.
1177 | + We can also nest conditionals: ~A₁ -> B₁; ⋯; Aₙ -> Bₙ; C~ ---again, ~C~ is optional.
1178 |
1179 | /We may use this form when we have disjoint conditions ~Aᵢ~!/
1180 |
1181 | However, using multiple clauses is preferable as it clearly separates concerns.
1182 |
1183 | ** Cut-fail Combination
1184 |
1185 | Suppose we want all solutions to ~p~ except ~e~, then we write:
1186 | #+BEGIN_SRC prolog :tangle no
1187 | all_but_e(X) :- X = e, !, fail.
1188 | all_but_e(X) :- p(X).
1189 | #+END_SRC
1190 |
1191 | When we pose the query ~all_but_e(e)~, the first rule applies, and we
1192 | reach the cut. This commits us to the choices we have made, and in
1193 | particular, blocks access to the second rule. But then we hit
1194 | ~fail~. This tries to force backtracking, but the cut blocks it, and so
1195 | our query fails ---as desired.
1196 |
1197 | # Red cut since it depends on the cut; without it the logic isn't enough
1198 | # to ensure the same meaning.
1199 | We can package up this red cut into a reusable form, ‘negation as failure’:
1200 | #+BEGIN_SRC prolog :tangle no
1201 | % neg(Goal) succeeds iff Goal fails.
1202 | neg(Goal) :- Goal, !, fail.
1203 | neg(Goal).
1204 |
1205 | all_but_e(X) :- p(X), neg(X = e).
1206 | #+END_SRC
1207 | The built-in prefix operator ~\+~ is negation as failure
1208 | ---you may use ~not(⋯)~ but must use the parens and no space before them.
1209 |
1210 | | /Remember: Order matters with Prolog's conjunction/! |
1211 |
1212 | Hence, ~\+ X = e, p(X)~ always fails ---see ~neg~ above---
1213 | but ~p(X), \+ X = e~ yields all solutions to ~p~ except ~e~.
1214 |
1215 | :Not_always_cut_clear:
1216 | Suppose ~p~ holds if ~a~ and ~b~ hold, or if ~a~ does not hold and ~c~ holds too.
1217 | Moreover, suppose ~a~ takes a lot of time to compute; then the program
1218 | on the right, with the red cut, is faster.
1219 | #+BEGIN_SRC prolog :tangle no
1220 | p :- a, b.
1221 | p :- \+ a, c
1222 |
1223 | p :- a, !, b.
1224 | p :- c.
1225 |
1226 | % or just a conditional
1227 | p :- a -> b; c
1228 | #+END_SRC
1229 | :End:
1230 |
1231 | ** Good Exercise
1232 |
1233 | Comprehension Exercise: With the left-side database, answer the right-side queries.
1234 | #
1235 | #+begin_parallel org
1236 | #+BEGIN_SRC prolog :tangle no
1237 | p(1).
1238 | p(2) :- !.
1239 | p(3).
1240 | #+END_SRC
1241 | #+latex: \columnbreak
1242 | #+BEGIN_SRC prolog :tangle no
1243 | ?- p(X).
1244 | ?- p(X), p(Y).
1245 | ?- p(X), !, p(Y).
1246 | #+END_SRC
1247 | #+end_parallel
1248 | :answers:
1249 | #+BEGIN_SRC prolog :tangle no
1250 | p(X) ⇒ 1, 2
1251 | p(X), p(Y) ⇒ 1-1, 1-2, 2-1, 2-2
1252 | p(X), !, p(Y) ⇒ 1-1, 1-2
1253 | #+END_SRC
1254 | :end:
1255 |
1256 | ** COMMENT Gibberish
1257 |
1258 | + Ensure deterministic behaviour:
1259 | Discard choice points of ancestor frames.
1260 |
1261 | - Once a goal has been satisfied, don't try anymore.
1262 | ---Efficient: We wont bother going through all possibilities,
1263 | the first solution found is sufficient for our needs.
1264 |
1265 | - When a cut, ~“!”~, is encountered, the system is committed to all choices
1266 | made since the parent goal was invoked. All other alternatives are discarded.
1267 |
1268 | + ~p(X, a), !~ only produces one answer to ~X~:
1269 | Do not search for additional solutions once /a/ solution has been found to ~p~.
1270 |
1271 | E.g., only one ~X~ solves the problem and trying to
1272 | find another leads to infinite search ---“green cut”---
1273 | or unintended candidate results ---“red cut”.
1274 |
1275 | * spacing newpage :ignore:
1276 | #+latex: \columnbreak
1277 | # \vfill
1278 | * Higher-order Support with ~call~
1279 |
1280 | #
1281 | #+begin_parallel org
1282 | Prolog is limited to first-order logic: We cannot bind variables to relations.
1283 |
1284 | Prolog /indirectly/ supports higher-order rules.
1285 |
1286 | #+latex: \columnbreak
1287 | #+BEGIN_SRC prolog
1288 | colour(bike, red).
1289 | colour(chair, blue).
1290 |
1291 | % Crashes!
1292 | % is_red(C, X, Y) :- C(X, Y)
1293 |
1294 | % Works
1295 | is_red(C, X, Y) :- call(C, X, Y).
1296 |
1297 | % ?- is_red(colour, bike, X).
1298 | %⇒ X = red.
1299 | #+END_SRC
1300 | #+end_parallel
1301 |
1302 | Translate between an invocation and a list representation by using ‘equiv’ ~=..~
1303 | as follows:
1304 | #+BEGIN_SRC prolog :tangle no
1305 | ?- p(a, b, c) =.. Y. %⇒ Y = [p, a, b, c].
1306 | ?- Y =.. [p, a, b, c]. %⇒ Y = p(a, b, c).
1307 | #+END_SRC
1308 |
1309 | * spacing COMMENT newpage :ignore:
1310 | #+latex: \columnbreak
1311 | # \vfill
1312 | * Meta-Programming
1313 |
1314 | Programs as data: Manipulating Prolog programs with other Prolog programs.
1315 |
1316 | ~clause(X, Y~) succeeds when ~X~ is the signature of a relation in the knowledge base,
1317 | and ~Y~ is the body of one of its clauses. ~X~ must be provided in the form ~f(X₁, …, Xₙ)~.
1318 | #+BEGIN_SRC prolog
1319 | test(you, me, us).
1320 | test(A, B, C) :- [A, B, C] = [the, second, clause].
1321 |
1322 | % ?- clause(test(Arg1, Arg2, Arg3), Body).
1323 | % ⇒ ‘Body’ as well as ‘Arg𝒾’ are unified for each clause of ‘test’.
1324 | #+END_SRC
1325 |
1326 | Here is a Prolog interpreter in Prolog ---an approximation to ~call~.
1327 | #+BEGIN_SRC prolog
1328 | % interpret(G) succeeds as a goal exactly when G succeeds as a goal.
1329 |
1330 | % Goals is already true.
1331 | interpret(true) :- !.
1332 |
1333 | % A pair of goals.
1334 | interpret((G, H)) :- !, interpret(G), interpret(H).
1335 |
1336 | % Simple goals: Find a clause whose head matches the goal
1337 | % and interpret its subgoals.
1338 | interpret(Goal) :- clause(Goal,Subgoals), interpret(Subgoals).
1339 |
1340 | % ?- interpret(test(A, B, C)).
1341 | #+END_SRC
1342 |
1343 | Challenge: There are many shortcomings with this interpreter, such as no support for interpreting
1344 | recursive functions, negation, failures, and disjunctions. Fix it!
1345 |
1346 | ** spacing newpage :ignore:
1347 | #+latex: \columnbreak
1348 | # \vfill
1349 | ** ~Print, var, nonvar, arg~
1350 | The ~print~ predicate always succeeds, never binds any variables, and prints out its
1351 | parameter as a side effect.
1352 |
1353 | #+latex: \vspace{1em}
1354 | Use built-ins ~var~ and ~nonvar~ to check if a variable is free or bound.
1355 | #+BEGIN_SRC prolog :tangle no
1356 | ?- var(Y). %⇒ true
1357 | ?- Y = 2, var(Y). %⇒ false
1358 | ?- Y = 2, nonvar(Y). %⇒ true
1359 | #+END_SRC
1360 |
1361 | #+latex: \vspace{1em}
1362 | Built-in ~arg(N,T,A~) succeeds if ~A~ is the ~N~-th argument of the term ~T~.
1363 | #+BEGIN_SRC prolog
1364 | % ?- arg(2, foo(x, y), y). %⇒ true
1365 | #+END_SRC
1366 |
1367 | * Reads
1368 | #+latex: .\vspace{-1.5em}
1369 | + [X] [[https://www.matchilling.com/introduction-to-logic-programming-with-prolog/][Introduction to logic programming with Prolog]] ---12 minute read.
1370 | + [X] [[http://www.doc.gold.ac.uk/~mas02gw/prolog_tutorial/prologpages/index.html#menu][Introduction to Prolog]] ---with interactive quizzes
1371 | + [ ] [[https://www.youtube.com/watch?v=SykxWpFwMGs][Derek Banas' Prolog Tutorial]] ---1 hour video
1372 | + [X] [[https://blog.algorexhealth.com/2018/11/a-practo-theoretical-introduction-to-logic-programming/][A Practo-Theoretical Introduction to Logic Programming]] ---a *colourful* read showing Prolog ≈ SQL.
1373 | + [ ] [[https://en.wikibooks.org/wiki/Prolog][Prolog Wikibook]] ---slow-paced and cute
1374 | + [ ] [[http://www.cs.nuim.ie/~jpower/Courses/Previous/PROLOG/][James Power's Prolog Tutorials]]
1375 | + [X] [[https://www3.risc.jku.at/education/courses/ws2009/logic-programming/][Introduction to Logic Programming Course]] ---Nice slides
1376 | + [ ] [[https://stackoverflow.com/questions/tagged/prolog][Stackoverflow Prolog Questions]] ---nifty FAQ stuff
1377 | + [ ] [[https://sites.google.com/site/prologsite/prolog-problems][99 Prolog Problems]] ---with solutions
1378 | + [ ] [[https://www.metalevel.at/prolog][The Power of Prolog]] --up to date tutorial, uses libraries ;-)
1379 | + [ ] [[https://www.cis.upenn.edu/~matuszek/cit594-2012/Pages/backtracking.html][Backtracking]]
1380 | + [ ] [[http://web.engr.oregonstate.edu/~erwig/papers/Zurg_JFP04.pdf][Escape from Zurg: An Exercise in Logic Programming]]
1381 | + [ ] [[https://www3.risc.jku.at/education/courses/ws2009/logic-programming/additional/Covington-Efficient-Prolog.pdf][Efficient Prolog]] --Practical tips
1382 | + [ ] [[https://pdfs.semanticscholar.org/57d3/1ca47fa9688089b9b7e7c19c199aa03aff1e.pdf][Use of Prolog for developing a new programming language]] ---Erlang!
1383 | + [ ] [[https://www.cpp.edu/~jrfisher/www/prolog_tutorial/pt_framer.html][prolog :- tutorial]] ---Example oriented
1384 | + [ ] [[http://www.learnprolognow.org/][Learn Prolog Now!]] (or [[http://cs.union.edu/~striegnk/learn-prolog-now/html/index.html][here]]) ---thorough, from basics to advanced
1385 | + [ ] [[http://www.pathwayslms.com/swipltuts/index.html][Real World Programming in SWI-Prolog]]
1386 | + [ ] [[https://www.amzi.com/AdventureInProlog/a1start.php][Adventures in Prolog]] ---Amzi! inc.
1387 | # + https://learnxinyminutes.com/docs/prolog/
1388 | # + [[http://faculty.nps.edu/ncrowe/book/chap14.html][Prolog's Logical Limitations]]
1389 |
1390 | # Prolog versus you, https://www.springer.com/gp/book/9783540175773
1391 |
1392 | # Chapter 2, problem-oriented
1393 | # http://www.anclp.pl/download/AN_CLP.pdf
1394 |
1395 | #+latex: \vspace{2em}
1396 | | Also, here's [[https://people.eng.unimelb.edu.au/adrianrp/COMP90054/lectures/Prolog_Coding.pdf][a nice set of 552 slides]] ^_^ |
1397 |
1398 | * COMMENT Misc
1399 | ** Coding in transitivity recursively
1400 | #+BEGIN_SRC prolog
1401 | taller(bob, mike).
1402 | taller(mike, jim).
1403 | taller(jim, george).
1404 |
1405 | taller(X, Y) :- taller(X, Z), taller(Z, Y).
1406 |
1407 | % ?- taller(bob, george). %⇒ true
1408 | % ?- taller(X, Y). %⇒ stack overflow
1409 |
1410 | % better one: Transitivity is 1 or more steps.
1411 | ttaller(X, Y) :- taller(X, Y).
1412 | ttaller(X, Y) :- taller(X, Z), ttaller(Z, Y).
1413 |
1414 | % ?- ttaller(bob, george). %⇒ true
1415 | % ?- ttaller(X, Y). %⇒ stack overflow
1416 | #+END_SRC
1417 |
1418 | ** [[http://cs.union.edu/~striegnk/learn-prolog-now/html/node21.html#sec.l2.exercises][Making a crossword puzzle generator.]]
1419 | Neato ^_^
1420 | #+BEGIN_SRC prolog
1421 | word(abalone,a,b,a,l,o,n,e).
1422 | word(abandon,a,b,a,n,d,o,n).
1423 | word(enhance,e,n,h,a,n,c,e).
1424 | word(anagram,a,n,a,g,r,a,m).
1425 | word(connect,c,o,n,n,e,c,t).
1426 | word(elegant,e,l,e,g,a,n,t).
1427 |
1428 | crosswd(V1, V2, V3, H1, H2, H3) :-
1429 | word(V1, V1C1, V1C2, V1C3, V1C4, V1C5, V1C6, _)
1430 | , word(V2, V2C1, V2C2, V2C3, V2C4, V2C5, V2C6, _)
1431 | , word(V3, V3C1, V3C2, V3C3, V3C4, V3C5, V3C6, _)
1432 | , word(H1, H1C1, H1C2, H1C3, H1C4, H1C5, H1C6, _)
1433 | , word(H2, H2C1, H2C2, H2C3, H2C4, H2C5, H2C6, _)
1434 | , word(H3, H3C1, H3C2, H3C3, H3C4, H3C5, H3C6, _)
1435 | , V1C2 = H1C2, V2C2 = H1C4, V3C2 = H1C6
1436 | , V1C4 = H2C2, V2C4 = H2C4, V3C4 = H2C6
1437 | , V1C6 = H3C2, V2C6 = H3C4, V3C6 = H3C6.
1438 | #+END_SRC
1439 |
1440 | * COMMENT Making README.md
1441 |
1442 | C-c C-c: Evaluate src block.
1443 |
1444 | #+NAME: make-readme
1445 | #+BEGIN_SRC elisp :results none
1446 | (with-temp-buffer
1447 | (insert
1448 | "#+EXPORT_FILE_NAME: README.md
1449 | ,#+HTML: PrologCheatSheet
1450 | ,#+OPTIONS: toc:nil d:nil
1451 | # Toc is displayed below at a strategic position.
1452 |
1453 | Basics of relational programming with Prolog
1454 | ---PROgramming in LOGic
1455 | ^_^
1456 |
1457 | [[https://swish.swi-prolog.org/p/algorex_prolog.pl][Try Prolog online]]
1458 |
1459 | ,*The listing sheet, as PDF, can be found
1460 | [here]({{{URL}}}/blob/master/CheatSheet.pdf)*,
1461 | while below is an unruly html rendition.
1462 |
1463 | This reference sheet is built around the system
1464 | https://github.com/alhassy/CheatSheet.
1465 |
1466 | ,#+TOC: headlines 2
1467 | ,#+INCLUDE: CheatSheet.org
1468 | ")
1469 | (org-mode)
1470 | (org-md-export-to-markdown)
1471 | )
1472 | #+END_SRC
1473 |
1474 | * COMMENT footer
1475 |
1476 | # Local Variables:
1477 | # eval: (org-babel-tangle)
1478 | # eval: (progn (org-babel-goto-named-src-block "make-readme") (org-babel-execute-src-block) (outline-hide-sublevels 1))
1479 | # eval: (load-file "CheatSheet.el")
1480 | # compile-command: (org-latex-export-to-pdf)
1481 | # End:
1482 |
--------------------------------------------------------------------------------