├── _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 | 92 | 93 | 94 |
Prolog is PROgramming in LOGic.
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 | 252 | 253 | 254 |
*This’ an excellent way to learn how Prolog proof search works! (Debugging!)*
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 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 |
SyntaxSemantics
`head(X) :- body(X,Y).`\(∀ X.\, head(X) \,⇐\, ∃ Y.\, body(X,Y)\)
`?- Q(X)`\(∃ X.\, Q(X)\)
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 | 358 | 359 | 360 | 361 | 362 |
`f(⋯X⋯) :- X = ℰ𝓍𝓅𝓇.``f(⋯ℰ𝓍𝓅𝓇⋯).`
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 | 386 | 387 | 388 | 389 | 390 | 391 |
Documentation Convention:`f/N`*relation `f` takes `N`-many arguments*
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 | 456 | 457 | 458 |
`⋯ℰ𝓍𝓅𝓇⋯ℰ𝓍𝓅𝓇⋯``X = ℰ𝓍𝓅𝓇, ⋯X⋯X⋯`
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 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 |
 \((p ⇐ q) ∧ (p ⇐ r)\)
 
 \(p ⇐ (q ∨ p)\)
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 | 561 | 562 | 563 |
**Thus variables are single ‘assignment’!**
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 | 580 | 581 | 582 |
*Unification lets us solve equations!* It lets us **compute!**
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 | 705 | 706 | 707 |
`𝓁 =:= 𝓇``L is 𝓁, R is 𝓇, L = R`.
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 `# 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 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 |
`p(X), q(Y)`\(\{ (x, y) ❙ p\, x \,∧\, q\, y\}\)
`p(X), !, q(Y)`\(\{ (x₁, y) ❙ q\, y\}\)
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 | 985 | 986 | 987 | 988 |
`A -> B; C`If `A` is true, then prove `B` and ignore `C`; else prove `C` and ignore `B`.
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 | 1033 | 1034 | 1035 |
*Remember: Order matters with Prolog's conjunction*!
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 | 1176 | 1177 | 1178 |
Also, here's [a nice set of 552 slides](https://people.eng.unimelb.edu.au/adrianrp/COMP90054/lectures/Prolog_Coding.pdf) ^\_^
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 ~# 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 | --------------------------------------------------------------------------------