{"id":16313453,"url":"https://github.com/alhassy/prologcheatsheet","last_synced_at":"2025-03-20T21:31:56.090Z","repository":{"id":43598576,"uuid":"188617093","full_name":"alhassy/PrologCheatSheet","owner":"alhassy","description":"Basics of relational programming with Prolog —PROgramming in LOGic ^_^","archived":false,"fork":false,"pushed_at":"2020-09-16T12:20:14.000Z","size":1209,"stargazers_count":70,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-11T21:51:25.776Z","etag":null,"topics":["cheatsheet","emacs","html","pdf","prolog","relational-programming"],"latest_commit_sha":null,"homepage":"","language":"Prolog","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alhassy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-25T22:15:49.000Z","updated_at":"2024-08-15T02:30:35.000Z","dependencies_parsed_at":"2022-09-04T14:23:15.875Z","dependency_job_id":null,"html_url":"https://github.com/alhassy/PrologCheatSheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2FPrologCheatSheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2FPrologCheatSheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2FPrologCheatSheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2FPrologCheatSheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alhassy","download_url":"https://codeload.github.com/alhassy/PrologCheatSheet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244085005,"owners_count":20395523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cheatsheet","emacs","html","pdf","prolog","relational-programming"],"created_at":"2024-10-10T21:51:16.894Z","updated_at":"2025-03-20T21:31:55.784Z","avatar_url":"https://github.com/alhassy.png","language":"Prolog","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1\u003e PrologCheatSheet \u003c/h1\u003e\n\nBasics of relational programming with Prolog\n\u0026#x2014;PROgramming in LOGic\n^\\_^\n\n[Try Prolog online](https://swish.swi-prolog.org/p/algorex_prolog.pl)\n\n**The listing sheet, as PDF, can be found\n[here](\u003chttps://github.com/alhassy/PrologCheatSheet/blob/master/CheatSheet.pdf\u003e)**,\nwhile below is an unruly html rendition.\n\nThis reference sheet is built around the system\n\u003chttps://github.com/alhassy/CheatSheet\u003e.\n\n\n# Table of Contents\n\n1.  [Administrivia](#org944e9a2)\n2.  [Syntax](#org1631a81)\n    1.  [`name` and `atom_chars`](#org01cff87)\n3.  [Facts \u0026 Relations](#org11a6a80)\n4.  [Mixfix Syntax](#org7e5c51a)\n5.  [Trace \u0026 Backtracking](#org7b75a05)\n6.  [What is a Prolog Program Exactly?](#orgd201c75)\n    1.  [One point rule](#org67c9d9a)\n    2.  [Overloading](#org0bf2d9a)\n7.  [Modus Ponens \u0026#x2014; Computation ≈ Deduction](#org3dc81b4)\n8.  [Conjunction ≈ Constraints \u0026#x2014; Disjunction ≈ Alternatives](#org0815789)\n9.  [Unification](#orgaabb8fb)\n    1.  [Operational Semantics](#org15dfa67)\n    2.  ['symbol' = symbol](#org8ef5c60)\n    3.  [Unification performs no simplification, whence no arithmetic](#orga3a1299)\n10. [Algebraic Datatypes](#org6447078)\n11. [Arithmetic with `is` \u0026#x2014;Using Modules](#org4994886)\n    1.  [Using Modules](#org86bbea7)\n12. [Lists](#orge54ab30)\n13. [Declaration Ordering Matters \u0026#x2014;Recursion](#org9e00a34)\n14. [The Cut](#org0df11fd)\n    1.  [Examples](#orgba67465)\n    2.  [Disjoint Clauses](#org23e01e5)\n    3.  [Conditional](#org0e85739)\n    4.  [Cut-fail Combination](#orgdbae64d)\n    5.  [Good Exercise](#org84fe2d7)\n15. [Higher-order Support with `call`](#orgc8294a3)\n16. [Meta-Programming](#org3072386)\n    1.  [`Print, var, nonvar, arg`](#org17ed3b0)\n17. [Reads](#orge425102)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca id=\"org944e9a2\"\u003e\u003c/a\u003e\n\n# Administrivia\n\n*Everything is a relation!* \u0026#x2014;I.e., a table in a database!\n\nWhence programs are [unidirectional](https://blog.algorexhealth.com/2018/11/a-practo-theoretical-introduction-to-logic-programming/) and can be ‘run in reverse’:\nInput arguments and output arguments are the same\nthing! Only perspective shifts matter.\n\nFor example, defining a relation `append(XS, YS, ZS)`\n*intended* to be true precisely when `ZS` is the catenation of `XS` with `YS`,\ngives us three other methods besides being a predicate itself!\nList construction: `append([1, 2], [3, 4], ZS)` ensures `ZS` is the catenation list.\nList subtraction: `append([1,2], YS, [1, 2, 3, 4])` yields all solutions `YS` to\nthe problem `[1, 2] ++ YS = [1, 2, 3, 4]`.\nPartitions: `append(XS, YS, [1, 2, 3, 4])` yields all pairs of lists that catenate\nto `[1,2, 3, 4]`. **Four methods for the price of one!**\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003eProlog is PROgramming in LOGic.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\nIn Prolog, the task of the programmer is simply to *describe* problems\n\u0026#x2014;write down, logically, the situation\u0026#x2014; rather than telling the computer\nwhat to do, then obtains information by asking questions\n\u0026#x2014;the logic programming system *figures out how* to get the answer.\n\n-   Prolog is declarative: A program is a collection of ‘axioms’ from which ‘theorems’\n    can be proven. For example, consider how sorting is performed:\n\n    -   Procedurally: Find the minimum in the remainder of the list, swap it with the head\n        of the list; repeat on the tail of the list.\n\n    -   Declaratively: `B` is the sorting of `A` *provided* it is a permutation of `A` and it is\n        ordered.\n\n    Whence, a program is a theory and computation is deduction!\n\n-   `swipl -s myprogram.pl` \u0026#x2013;Load your program into a REPL, `?-….`\n-   `make.` \u0026#x2013;Reload your program.\n-   `halt.` \u0026#x2013;Exit the REPL.\n-   `consult('CheatSheet.pl').` \u0026#x2013;Load the contents of the given file as\n    the new knowledge base.\n-   `assert((⋯)).` \u0026#x2013;Add a new rule to the knowledge base, from within the REPL.\n    Use `retract((⋯))` to remove rules from the knowledge base.\n    -   `assert` is useful when we want to [cache](http://cs.union.edu/~striegnk/learn-prolog-now/html/node94.html#sec.l11.database.manip) computations.\n-   `listing.` \u0026#x2013;Display the contents of the current knowledge base; i.e.,\n    what Prolog ‘knows’.\n-   `listing(name)`. \u0026#x2013;List all information in the knowledge base about\n    the `name` predicate.\n\n\n\u003ca id=\"org1631a81\"\u003e\u003c/a\u003e\n\n# Syntax\n\nThere are three types of terms:\n\n-   Constants: Numbers such as -24, and atoms such as `jasim`, `'hello world'`,\n    `'\u0026^%\u0026#@$ \u0026*',` and `' '` \u0026#x2014;a space in quotes.\n-   Variables: Words starting with a capital letter or an underscore.\n    -   The variable `_` is called the *anonymous variable*.\n\n        It's for when we need a variable, say when pattern matching,\n        but don't care about the value.\n\n-   Structures: Terms of the form `functor(term₁,...,termₙ)`.\n\n\n\u003ca id=\"org01cff87\"\u003e\u003c/a\u003e\n\n## `name` and `atom_chars`\n\nThe characters between single quotes are the *name* of an atom\nand so Prolog admits `symbol = 'symbol'` as true.\n\n-   Atoms, or nullary predicates, are represented as a lists of numbers; ASCII codes.\n-   We can use this to compare two atoms lexicographically.\n-   We can obtain the characters in an atom by using the built-in `atom_chars`.\n\n    ?- name(woah, X).       %⇒ X = [119,111,97,104]\n    ?- atom_chars(nice, X). %⇒ X = [n, i, c, e].\n\n\n\u003ca id=\"org11a6a80\"\u003e\u003c/a\u003e\n\n# Facts \u0026 Relations\n\nWe declare relations by having them begin with a lowercase letter;\nvariables are distinguished by starting with a capital letter.\n\n\u003cdiv class=\"parallel\"\u003e\n    /* Some facts of our world */\n    jasim_is_nice.\n    it_is_raining.\n\n    % ?- jasim_is_nice.\n    % ⇒ true: We declared it so.\n\n    eats(fred, mangoes).\n    eats(bob, apples).\n    eats(fred, oranges).\n\n    % Which foods are eaten by fred?\n    % ?- eats(fred, what).\n         %⇒ false; “what” is a name!\n    % ?- eats(fred, What). %⇒ mangoes oranges\n\n\u003c/div\u003e\n\nRelational constraints are formed using `:-`, which acts as the “provided”, ⇐,\noperator from logic. Read `P :- Q` as *P is true, provided Q is true.*\n\n\u003cdiv class=\"parallel\"\u003e\n    % All men are mortal.\n    mortal(X) :- man(X).\n\n    % Socrates is a man.\n    man(socrates).\n\n    % Hence, he's expected to be mortal.\n    % ?- mortal(socrates). %⇒ true\n\n    % What about Plato?\n    ?- mortal(plato).\n    %⇒ false, plato's not a man.\n\n    % Let's fix that … in the REPL!\n    ?- assert((man(plato))).\n\n    % Who is mortal?\n    ?- mortal(X). % ⇒ socrates plato\n\n\u003c/div\u003e\n\n\n\u003ca id=\"org7e5c51a\"\u003e\u003c/a\u003e\n\n# [Mixfix Syntax](http://cs.union.edu/~striegnk/learn-prolog-now/html/node84.html#subsec.l9.operators.def)\n\n\u003cdiv class=\"parallel\"\u003e\n  It may feel awkward to write `father_of(homer, bart)` and instead prefer\n`homer father_of bart`. We may declare relations to be prefix, infix, or postfix\nwith patterns `xf`, `xfx`, and `fx` respectively. For left associativity\nwe use pattern `yfx` and use `xfy` for right associativity.\n\n    :- op(35,xfx,father_of).\n\n    father_of(me, you).\n    homer father_of bart.\n    homer father_of lisa.\n\n\u003c/div\u003e\n\n-   Precedence, or binding power, is lowest at 1200 and highest at 0.\n-   Note: `father_of(X,Y) = X father_of Y` is true.\n\nWe may learn about existing operators too;\n\ne.g., `?- current_op(Prec, Fixity, =:=)` ^\\_^\n\n\n\u003ca id=\"org7b75a05\"\u003e\u003c/a\u003e\n\n# Trace \u0026 Backtracking\n\nWe can see what Prolog does at each step of a computation by invoking\n`trace`; we turn off this feature with `notrace.`\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e*This’ an excellent way to learn how Prolog proof search works! (Debugging!)*\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003cdiv class=\"parallel\"\u003e\nSuppose we have the following database.\n\n    q(1). q(2). q(3).\n    r(2). r(3).\n    p(X) :- q(X), r(X).\n\nWith trace, query `p(X)` and press\n*SPACE* each time to see what\nProlog is doing.\nAt one point, the goal `r(1)` will\n*fail* and that choice \\(X = 1\\)\nwill be redone with the next possibility\nfor `q`, namely \\(X = 2\\).\n\n\u003c/div\u003e\n\nThe line marked `redo` is when Prolog realizes its taken the wrong\npath, and backtracks to instantiate the variable to 2.\n\nOperationally, query `p(X)` is answered by:\n\n1.  Find match for the first goal: `q` at `1`.\n2.  Then see if matches the second: `r` at `1`.\n3.  (Redo) If not, find another match for the first: `q` at `2`.\n4.  See if this matches the second, `r`.\n5.  Etc.\n\n-   `findall(X, Goal, L)` succeeds if `L` is the list of all those `X`'s for\n    which `Goal` holds.\n\n-   `fail/0` immediately fails when encountered. Remember: Prolog tries to\n    backtrack when its fails; whence `fail` can be viewed as an\n    instruction to force backtracking.\n\n    The opposite of forcing backtracking is to block it, which is done\n    with ‘cut’ `!` \u0026#x2014;see below.\n\n\n\u003ca id=\"orgd201c75\"\u003e\u003c/a\u003e\n\n# What is a Prolog Program Exactly?\n\nA program *denotes* all true facts derivable from its clauses using\n**modus ponens, unification, term rewriting, and logical or-\u0026-and**\nfor the execution model.\n\nHidden Quantifiers:\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e\u003cspan class=\"underline\"\u003eSyntax\u003c/span\u003e\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e\u003cspan class=\"underline\"\u003eSemantics\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\n\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e`head(X) :- body(X,Y).`\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e\\(∀ X.\\, head(X) \\,⇐\\, ∃ Y.\\, body(X,Y)\\)\u003c/td\u003e\n\u003c/tr\u003e\n\n\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e`?- Q(X)`\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e\\(∃ X.\\, Q(X)\\)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n1.  “ `head(X)` is true provided there's some `Y` such that `body(X,Y)` is true ”\n    -   `head.` is an abbreviation for `head :- true.`\n    -   Indeed, \\(p \\;≡\\; (p ⇐ true)\\).\n2.  “ Is there an `X` so that `Q(X)` is true? ”\n\n\n\u003ca id=\"org67c9d9a\"\u003e\u003c/a\u003e\n\n## One point rule\n\n“One-Point Rule”: Provided `X` is a fresh variable,\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e`f(⋯X⋯) :- X = ℰ𝓍𝓅𝓇.`\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e≈\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e`f(⋯ℰ𝓍𝓅𝓇⋯).`\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n\u003ca id=\"org0bf2d9a\"\u003e\u003c/a\u003e\n\n## Overloading\n\n*Overloading!* Predicates of different arities are considered different.\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003eDocumentation Convention:\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e`f/N`\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e≈\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e*relation `f` takes `N`-many arguments*\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n\u003ca id=\"org3dc81b4\"\u003e\u003c/a\u003e\n\n# Modus Ponens \u0026#x2014; Computation ≈ Deduction\n\nThe logical rule \\(p ∧ (p ⇒ q) \\;⇒\\; q\\) says if we have \\(p\\), and from\nthat we know we can get a \\(q\\), then we have a \\(q\\). From the following program\non the left, we get `q(a)` is true.\n\n\u003cdiv class=\"parallel\"\u003e\n    p(a).\n    q(X) :- p(X).\n\nWe *rewrite* term `X` with atom `a` to obtain `q(a) :- p(a)` from the second rule,\nbut we know `p(a)`, and so we have *computed* the new fact `q(a)` by using the\ndeduction rule modus ponens.\n\n\u003c/div\u003e\n\n\n\u003ca id=\"org0815789\"\u003e\u003c/a\u003e\n\n# Conjunction ≈ Constraints \u0026#x2014; Disjunction ≈ Alternatives\n\nConjunction: `p(X), q(X)` means “let `X` be *a* solution to `p`, then use it in query `q`.”\n\n\u003cdiv class=\"parallel\"\u003e\nOperational semantics: Let `X` be the first solution declared, found,\n  for `p`, in the user's script, then try `q`; if it fails, then *backtrack*\n  and pick the next declared solution to `p`, if any, and repeat until `q`\n  succeeds \u0026#x2014;if possible, otherwise fail.\n\n    yum(pie).\n    yum(apples).\n    yum(maths).\n\n    % ?- yum(Y), writeln(Y), fail.\n    %⇒ pie apples maths false.\n\n\u003c/div\u003e\n\n“Fail driven loop” `p(X), print(X), fail.` gets a solution to `p`, prints\nit, then fails thereby necessitating a backtrack to obtain a\ndifferent solution `X` for `p`, then repeats. In essence, this is prints\nall solutions to `p`.\n\n“Let Clauses”: Provided `X` is a fresh variable,\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e`⋯ℰ𝓍𝓅𝓇⋯ℰ𝓍𝓅𝓇⋯`\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e≈\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e`X = ℰ𝓍𝓅𝓇, ⋯X⋯X⋯`\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\nA Prolog program is the conjunction of all its clauses, alternatives ‘;’.\n\n\u003cdiv class=\"parallel\"\u003e\n    % (head ⇐ body₁) ∧ (head ⇐ body₂)\n    head :- body₁.\n    head :- body₂.\n    ≈\n    % head  ⇐  body₁ ∨ body₂\n    head :- body₁ ; body₂.\n\nRead ‘⇐’ as ‘≥’, and ‘∨’ as maximum, then the following is the\n“characterisation of least upper bounds”.\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e\u0026#xa0;\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e\\((p ⇐ q) ∧ (p ⇐ r)\\)\u003c/td\u003e\n\u003c/tr\u003e\n\n\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e≡\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e\u0026#xa0;\u003c/td\u003e\n\u003c/tr\u003e\n\n\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e\u0026#xa0;\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e\\(p ⇐ (q ∨ p)\\)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c/div\u003e\n\n“And binds stronger than Or”: `a,b;c ≈ (a,b);c`.\n\n\n\u003ca id=\"orgaabb8fb\"\u003e\u003c/a\u003e\n\n# [Unification](http://cs.union.edu/~striegnk/learn-prolog-now/html/node15.html)\n\nA program can be written by having nested patterns, terms, then we use\nmatching to pull out the information we want!\n\nTwo terms *match* or *unify*, if they are equal or if they contain variables that\ncan be instantiated in such a way that the resulting terms are equal.\n\n-   **Unification:** Can the given terms be made to represent the same structure?\n    -   This is how type inference is made to work in all languages.\n\n-   **Backtracking:** When a choice in unification causes it to fail, go back to the\n    most recent choice point and select the next available choice.\n    -   Nullary built-in predicate `fail` always fails as a goal and causes backtracking.\n\n\n\u003ca id=\"org15dfa67\"\u003e\u003c/a\u003e\n\n## Operational Semantics\n\n\u003cdiv class=\"parallel\"\u003e\nThe unification predicate is `=/2`. It can be written with the usual\nnotation `=(L, R)` but can also be written infix `L = R`.\n\n    % Query: Who is loved by Jay?\n    ?- loves(jay, X) = loves(jay, kathy).\n    % ⇒ X = kathy\n\n\u003c/div\u003e\n\nOperationally `ℒ = ℛ` behaves as follows:\n\n1.  If either is an unbound variable, assign it to the other one.\n    -   A constant unifies only with itself.\n    -   A variable unifies with anything.\n2.  Otherwise, they are both terms.\n    -   Suppose \\(ℒ ≈ f(e₁,…,eₙ)\\) and \\(ℛ ≈ g(d₁,…,dₘ)\\).\n    -   If `f` is different from `g`, or `n` different from `m`, then crash.\n    -   Recursively perform `eᵢ = dᵢ`.\n\n        Ensure the variable instantiations are compatible in that a\n        variable is associated with at most one value \u0026#x2014;which is\n        not true in `f(1,2) = f(X,X).`\n\n        \u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n        \u003ccolgroup\u003e\n        \u003ccol  class=\"org-left\" /\u003e\n        \u003c/colgroup\u003e\n        \u003ctbody\u003e\n        \u003ctr\u003e\n        \u003ctd class=\"org-left\"\u003e**Thus variables are single ‘assignment’!**\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003c/tbody\u003e\n        \u003c/table\u003e\n\n        Exception! Each occurrence of the anonymous variable `_`\n        is independent: Each is bound to something different.\n\n3.  If two terms can't be shown to match using the above clauses,\n    then they don't match.\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e*Unification lets us solve equations!* It lets us **compute!**\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n\u003ca id=\"org8ef5c60\"\u003e\u003c/a\u003e\n\n## 'symbol' = symbol\n\nThe query `'symbol' = symbol` is true since both are considered to be the same\natom. Whereas `'2' = 2` is false since `'2'` is a symbolic atom but `2` is a number.\n\nThe *discrepancy predicate* `\\=/2` succeeds when its arguments don't unify;\ne.g., `'5' \\= 5` is true.\n\n\n\u003ca id=\"orga3a1299\"\u003e\u003c/a\u003e\n\n## Unification performs no simplification, whence no arithmetic\n\n\u003cdiv class=\"parallel\"\u003e\n   Unification performs no simplification, whence no arithmetic.\nThis 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.\n\n    ?- C + \"nice\" = woah + Z.\n    C = woah, Z = \"nice\".\n\n    % ‘+’ and ‘/’ are different,\n    % so no way to make these equal.\n    ?- C + \"nice\" = woah / Z.\n    false.\n\n\u003c/div\u003e\n\n\n\u003ca id=\"org6447078\"\u003e\u003c/a\u003e\n\n# Algebraic Datatypes\n\nUniform treatment of all datatypes as predicates! Enumerations, pairs, recursives:\n\n\u003cdiv class=\"parallel\"\u003e\n\u003cspan class=\"underline\"\u003eHaskell\u003c/span\u003e\n\n    data Person = Me | You | Them\n\n\n\n    data Pair a b = MkPair a b\n\n    data Nat = Zero | Succ Nat\n\n\n    sum Zero     n = n\n    sum (Succ m) n = Succ (sum m n)\n\n\u003cspan class=\"underline\"\u003eProlog\u003c/span\u003e\n\n    person(me).\n    person(you).\n    person(them).\n\n    pair(_, _).\n\n    nat(zero).\n    nat(succ(N)) :- nat(N).\n\n    sum(zero, N, N).\n    sum(succ(M), N, succ(S))\n      :- sum(M, N, S).\n\n\u003c/div\u003e\n\nExercise: Form binary trees.\n\n\n\u003ca id=\"org4994886\"\u003e\u003c/a\u003e\n\n# Arithmetic with `is` \u0026#x2014;Using Modules\n\nUse `is` to perform arithmetic with `+, -, *, /, **, mod`, and\n`//` for integer division.\n\n    % How do we make this equation equal?\n    ?- X = 3 + 2.\n    % ⇒ X = 3 + 2; this choice of variables make its equal!\n\n    % Everything is a term! Terms don't ‘compute’!\n    ?- +(3, 2) = 3 + 2. % ⇒ true\n    ?- +(3, 2) = 6 - 1. % ⇒ false\n\n\u003cdiv class=\"parallel\"\u003e\n    ?- X is 3 + 2. % ⇒ X = 5\n    ?- 5 is 6 - 1. % ⇒ true\n    ?- 5 is X. % ⇒ CRASH!\n    ?- 3 + 2 is 6 - 1. %⇒ CRASH!\n\n    ?- +(3, 2) =:= 6 - 1. % ⇒ true\n    ?- 1 =:= sin(pi/2).   % ⇒ true\n    ?- X =:= 3 + 2.       % ⇒ CRASH!\n    ?- X = 2, Y = 3, X + Y =:= 5. % ⇒ true\n\n\u003c/div\u003e\n\n-   `is` takes a *variable, or a numeric constant,* and an arithmetical\n    expression as arguments.\n    -   `L is R` means “ unify `L` with the result of simplifying `R` ”\n    -   If `R` mentions an unbound variable, crash!\n-   `=:=` has both arguments as *concrete terms*, it evaluates them and compares the results.\n\n    \u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n    \u003ccolgroup\u003e\n    \u003ccol  class=\"org-left\" /\u003e\n\n    \u003ccol  class=\"org-left\" /\u003e\n\n    \u003ccol  class=\"org-left\" /\u003e\n    \u003c/colgroup\u003e\n    \u003ctbody\u003e\n    \u003ctr\u003e\n    \u003ctd class=\"org-left\"\u003e`𝓁 =:= 𝓇`\u003c/td\u003e\n    \u003ctd class=\"org-left\"\u003e≈\u003c/td\u003e\n    \u003ctd class=\"org-left\"\u003e`L is 𝓁, R is 𝓇, L = R`.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003c/tbody\u003e\n    \u003c/table\u003e\n\n\n\u003ca id=\"org86bbea7\"\u003e\u003c/a\u003e\n\n## Using Modules\n\n\u003cdiv class=\"parallel\"\u003e\n\n\nThe [Constraint Logic Programming over Finite Domains](http://www.swi-prolog.org/pldoc/man?section=clpfd) library provides a number of\nuseful functions, such as `all_distinct` for checking a list has unique elements.\n\nSee [here](http://www.swi-prolog.org/pldoc/man?section=clpfd-sudoku) for a terse solution to Sudoku.\n\nIn particular, `=:=` is too low level \u0026#x2014;e.g., it doesn't admit unbound variables\u0026#x2014;\ninstead one uses `clpfd`'s `#=/2` predicate.\n\nLikewise we could use `in` to check if a number is in a particular range, or instead use `#\u003e/2` and `#\u003c/2`.\n\n    use_module(library(clpfd)).\n\n    ?- all_distinct([1,\"two\", two]).\n\n    ?- X + 2 #= 3. %⇒ X = 1\n    ?- 1 + Y #= 3. %⇒ Y = 2.\n    ?- X #= Y.     %⇒ Also works ;-)\n\n    ?- 2 in 0..3.       %⇒ true.\n    ?- 3 #\u003e X, 0 #\u003c X.  %⇒ X in 1..2.\n\n    % All parititions of number N ^_^\n    ?- N = 5, between(0, N, X),\n       between(0, N, Y), X + Y #= N.\n\n\u003c/div\u003e\n\n\n\u003ca id=\"orge54ab30\"\u003e\u003c/a\u003e\n\n# Lists\n\nLists are enclosed in brackets, separated by commas, and can be split\nup at any point by using cons “|”. The empty list is `[]`.\n\n    ?- [\"one\", two, 3] = [Head|Tail].\n    %⇒ Head = \"one\", Tail = [two, 3].\n\n    ?- [\"one\", two, 3] = [_,Second|_].\n    %⇒ Second = two.\n\n    ?- [[the, Y], Z]   = [[X, hare], [is, here]].\n    %⇒ X = the, Y = hare, Z = [is, here]\n\nSearching: \\(x ∈ l\\)?\n\n    elem(Item, [Item|Tail]). % Yes, it's at the front.\n    elem(Item, [_|Tail]) :- elem(Item, Tail). % Yes, it's in the tail.\n\n    % ?- elem(one, [this, \"is\", one, thing]). %⇒ true\n    % ?- elem(onE, [this, \"is\", one, thing]). %⇒ false\n\nSee [here](http://www.swi-prolog.org/pldoc/man?section=lists) for the list library, which includes:\n\n\u003cdiv class=\"parallel\"\u003e\n    member(element, list)\n    append(list1, list2, lists12)\n    prefix(part, whole)\n    nth0(index, list, element)\n    last(list, element)\n    length(list, number)\n    reverse(list1, list2)\n    permutation(list1, list2)\n    sum_list(list, number)\n    max_list(list, number)\n    is_set(list_maybe_no_duplicates)\n\nIn Haskell, we may write `x:xs`, but trying that here forces us to write\n`[X|XS]` or `[X|Xs]` and accidentally mismatching the capitalisation of the ‘s’\ndoes not cause a compile-time error but will yield an unexpected logical error\n\u0026#x2013;e.g., in the recursive clause use `Taill` instead of `Tail`.\nAs such, prefer the `[Head|Tail]` or `[H|T]` naming.\n\n\u003c/div\u003e\n\nExercise: Implement these functions.\n\nHint: Arithmetic must be performed using `is`.\n\n\n\u003ca id=\"org9e00a34\"\u003e\u003c/a\u003e\n\n# Declaration Ordering Matters \u0026#x2014;Recursion\n\nProlog searches the knowledge base from top to bottom, clauses from\nleft to right, and uses backtracking to recover from bad choices.\n\nWhen forming a recursive relation, ensure the base case, the\nterminating portion, is declared before any portions that require\nrecursion. Otherwise the program may loop forever.\n\nUnification is performed using depth-first search using the order of\nthe declared relationships. For example, the following works:\n\n    % Acyclic graph: a ⟶ b ⟶ c ⟶ d\n    edge(a, b). edge(b ,c). edge(c, d).\n\n    % Works\n    path(X, X).\n    path(X, Y) :- edge(Z, Y)  % Can we get to Y from some intermediary Z?\n                , path(X, Z). % Can we get to the intermediary Z from X?\n    % ?- path(a, d). %⇒ true.\n\n    % Fails: To find a path, we have to find a path, before an edge!\n    % The recursive clause is first and so considerd before the base clause!\n    path_(X, Y) :- path_(X, Z), edge(Z, Y).\n    path_(X, X).\n    % ?- path_(a, d). %⇒ loops forever!\n\n\n\u003ca id=\"org0df11fd\"\u003e\u003c/a\u003e\n\n# The Cut\n\nAutomatic backtracking is great, but can be a waste of time exploring\npossibilities that lead nowhere. The atom *cut*, `!`, offers a way to\ncontrol how Prolog looks for solutions:\nIt always succeeds with a side-effect of committing to any choices made thus far\n\u0026#x2014;including variable instantiations **and** rule, clause, chosen\u0026#x2014;\nwhence ignoring any other possible branches and no backtracking!\n\n`q :- p₁, …, pₙ, !, r₁, …, rₘ`\n⇒ Once we reach the cut, we're commited to the choices made when evaluating the `pᵢ`,\nbut we are free to backtrack among the `rᵢ` **and** we may backtrack among the alternatives\nfor choices that were made before reaching goal `q`. Here's an example.\n\n\u003cdiv class=\"parallel\"\u003e\n    i(1). i(2).\n    j(1). j(2). j(3).\n\n    k(X, Y) :- i(X), !, j(Y).\n\n    l(X,Y) :- k(X,Y).\n    l(0,0).\n\n\u003c/div\u003e\n\nQuery `l(X, Y)` yields\nsolutions 1-1, 1-2, 1-3, and 0-0.\nNotice that `X = 0, Y = 0` is not\ntruthified by by the first clause of `l`\nbut the choice of clause happened before the `k`-clause\ncontaining the cut `!` and so backtracking may pick another `l`-clause.\nNotice that without the cut, we have the extra solutions 2-1, 2-2, 2-3\nwhich are “cut out” by `!` since `i(1)` is the choice we committed to for `X = 1`\nand we can backtrack for `Y` only since it comes after the cut.\n\nSuppose `x₁` is the first solution found for `p`, then:\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e`p(X), q(Y)`\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e≈\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e\\(\\{ (x, y) ❙ p\\, x \\,∧\\, q\\, y\\}\\)\u003c/td\u003e\n\u003c/tr\u003e\n\n\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e`p(X), !, q(Y)`\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e≈\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003e\\(\\{ (x₁, y) ❙ q\\, y\\}\\)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n\u003ca id=\"orgba67465\"\u003e\u003c/a\u003e\n\n## Examples\n\nRemember, the cut not only commits to the instantiations so far, but\nalso commits to the clause of the goal in which it occurs, whence no\nother clauses are even tried!\n\n    g(X) :- h(X), !, i(X).\n    g(X) :- j(X).\n\n    h(1). h(4). i(3). j(2).\n\n    % ?- g(X). %⇒ fails\n\nThere are two clauses to prove `g`, by default we pick the first one.\nNow we have the subgoal `h`, for which there are two clauses and we select\nthe first by default to obtain `X = 1`. We now encounter the cut which means\nwe have committed to the current value of `X` and the current clause to prove `g`.\nThe final subgoal is `i(1)` which is false. Backtracking does not allow us to select\ndifferent goals, and it does not allow us to use the second clause to prove `g`.\nWhence, `g(X)` fails. Likewise we fail for `g(4)`. Note that if we had failed `h`\nbefore the cut, as is the case with `g(2)`, then we fail that clause before encountering\nthe cut and so the second rule is tried.\n\n\n\u003ca id=\"org23e01e5\"\u003e\u003c/a\u003e\n\n## Disjoint Clauses\n\nWhen there are disjoint clauses, i.e., only one succeeds, then if\nbacktracking is forced at some point, trying other cases is a waste\nof time since only one clause, say the first one, succeeds.  An\nexample of this would be the maximum function or the \\(\\sum_{i=0}^n i\\) function.\n\n\u003cdiv class=\"parallel\"\u003e\n    max_(X, Y, Y) :- X =\u003c Y.\n    max_(X, Y, X) :- X \u003e Y.\n\n    % ?- trace.\n    % ?- max_(3, 4, Y).\n    % ⇒ Wastes time trying both clauses.\n\n    max(X, Y, Y) :- X =\u003c Y, !.\n    max(X, Y, X) :- X \u003e Y.\n\n    % ?- trace.\n    % ?- max(3, 4, Y).\n    % ⇒ Only first clause is tried ^_^\n\n    sum_to(0, 0).\n    sum_to(N, Res) :- M is N - 1,\n                      sum_to(M, ResM),\n                      Res is ResM + N.\n\n    % Example execution\n    % ?- sum_to(1, X).\n    % ⇒ Loops forever: Both clauses apply!\n\n    % The fix is to mark the\n    % first clause as a “base case”.\n    sum_to(0, 0) :- !.\n\n\u003c/div\u003e\n\nThe resulting code gives the *same* results but is more *efficient*.\nSuch cuts are called *green cuts*. Changes to a program that *depend*\non a cut rather than the logic are called *red cuts* and are best avoided\n\u0026#x2014;e.g., `maxNo(X, Y, Y) :- X =\u003c Y, !. maxNo(X, Y, X).` works by relying on the cut:\nIt works with variables, but `maxNo(2, 3, 2)` matches the second clause unconditionally\neven though 2 is not the maximum of 2 and 3!\n\n-   Cut at the end ⇒ Don't consider any more clauses of the current predicate.\n\n\n\u003ca id=\"org0e85739\"\u003e\u003c/a\u003e\n\n## Conditional\n\n**Lazy Conditional**\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e`A -\u003e B; C`\u003c/td\u003e\n\u003ctd class=\"org-left\"\u003eIf `A` is true, then prove `B` and ignore `C`; else prove `C` and ignore `B`.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n-   The “; C” portion is *optional* and `C` defaults to `fail`.\n-   We can also nest conditionals: `A₁ -\u003e B₁; ⋯; Aₙ -\u003e Bₙ; C` \u0026#x2014;again, `C` is optional.\n\n*We may use this form when we have disjoint conditions `Aᵢ`!*\n\nHowever, using multiple clauses is preferable as it clearly separates concerns.\n\n\n\u003ca id=\"orgdbae64d\"\u003e\u003c/a\u003e\n\n## Cut-fail Combination\n\nSuppose we want all solutions to `p` except `e`, then we write:\n\n    all_but_e(X) :- X = e, !, fail.\n    all_but_e(X) :- p(X).\n\nWhen we pose the query `all_but_e(e)`, the first rule applies, and we\nreach the cut.  This commits us to the choices we have made, and in\nparticular, blocks access to the second rule. But then we hit\n`fail`. This tries to force backtracking, but the cut blocks it, and so\nour query fails \u0026#x2014;as desired.\n\nWe can package up this red cut into a reusable form, ‘negation as failure’:\n\n    % neg(Goal) succeeds iff Goal fails.\n    neg(Goal) :- Goal, !, fail.\n    neg(Goal).\n\n    all_but_e(X) :- p(X), neg(X = e).\n\nThe built-in prefix operator `\\+` is negation as failure\n\u0026#x2014;you may use `not(⋯)` but must use the parens and no space before them.\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003e*Remember: Order matters with Prolog's conjunction*!\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\nHence, `\\+ X = e, p(X)` always fails \u0026#x2014;see `neg` above\u0026#x2014;\nbut `p(X), \\+ X = e` yields all solutions to `p` except `e`.\n\n\n\u003ca id=\"org84fe2d7\"\u003e\u003c/a\u003e\n\n## Good Exercise\n\nComprehension Exercise: With the left-side database, answer the right-side queries.\n\n\u003cdiv class=\"parallel\"\u003e\n    p(1).\n    p(2) :- !.\n    p(3).\n\n    ?- p(X).\n    ?- p(X), p(Y).\n    ?- p(X), !, p(Y).\n\n\u003c/div\u003e\n\n\n\n\u003ca id=\"orgc8294a3\"\u003e\u003c/a\u003e\n\n# Higher-order Support with `call`\n\n\u003cdiv class=\"parallel\"\u003e\nProlog is limited to first-order logic: We cannot bind variables to relations.\n\nProlog *indirectly* supports higher-order rules.\n\n    colour(bike, red).\n    colour(chair, blue).\n\n    % Crashes!\n    % is_red(C, X, Y) :- C(X, Y)\n\n    % Works\n    is_red(C, X, Y) :- call(C, X, Y).\n\n    % ?- is_red(colour, bike, X).\n    %⇒ X = red.\n\n\u003c/div\u003e\n\nTranslate between an invocation and a list representation by using ‘equiv’ `=..`\nas follows:\n\n    ?- p(a, b, c) =.. Y.   %⇒ Y = [p, a, b, c].\n    ?- Y =.. [p, a, b, c]. %⇒ Y = p(a, b, c).\n\n\n\n\u003ca id=\"org3072386\"\u003e\u003c/a\u003e\n\n# Meta-Programming\n\nPrograms as data: Manipulating Prolog programs with other Prolog programs.\n\n`clause(X, Y`) succeeds when `X` is the signature of a relation in the knowledge base,\nand `Y` is the body of one of its clauses. `X` must be provided in the form `f(X₁, …, Xₙ)`.\n\n    test(you, me, us).\n    test(A, B, C) :- [A, B, C] = [the, second, clause].\n\n    % ?- clause(test(Arg1, Arg2, Arg3), Body).\n    % ⇒ ‘Body’ as well as ‘Arg𝒾’ are unified for each clause of ‘test’.\n\nHere is a Prolog interpreter in Prolog \u0026#x2014;an approximation to `call`.\n\n    % interpret(G) succeeds as a goal exactly when G succeeds as a goal.\n\n    % Goals is already true.\n    interpret(true) :- !.\n\n    % A pair of goals.\n    interpret((G, H)) :- !, interpret(G), interpret(H).\n\n    % Simple goals: Find a clause whose head matches the goal\n    %               and interpret its subgoals.\n    interpret(Goal) :- clause(Goal,Subgoals), interpret(Subgoals).\n\n    % ?- interpret(test(A, B, C)).\n\nChallenge: There are many shortcomings with this interpreter, such as no support for interpreting\nrecursive functions, negation, failures, and disjunctions. Fix it!\n\n\n\u003ca id=\"org17ed3b0\"\u003e\u003c/a\u003e\n\n## `Print, var, nonvar, arg`\n\nThe `print` predicate always succeeds, never binds any variables, and prints out its\nparameter as a side effect.\n\nUse built-ins `var` and `nonvar` to check if a variable is free or bound.\n\n    ?- var(Y).           %⇒ true\n    ?- Y = 2, var(Y).    %⇒ false\n    ?- Y = 2, nonvar(Y). %⇒ true\n\nBuilt-in `arg(N,T,A`) succeeds if `A` is the `N`-th argument of the term `T`.\n\n    % ?- arg(2, foo(x, y), y). %⇒ true\n\n\n\u003ca id=\"orge425102\"\u003e\u003c/a\u003e\n\n# Reads\n\n-   [X] [Introduction to logic programming with Prolog](https://www.matchilling.com/introduction-to-logic-programming-with-prolog/) \u0026#x2014;12 minute read.\n-   [X] [Introduction to Prolog](http://www.doc.gold.ac.uk/~mas02gw/prolog_tutorial/prologpages/index.html#menu) \u0026#x2014;with interactive quizzes\n-   [ ] [Derek Banas' Prolog Tutorial](https://www.youtube.com/watch?v=SykxWpFwMGs)  \u0026#x2014;1 hour video\n-   [X] [A Practo-Theoretical Introduction to Logic Programming](https://blog.algorexhealth.com/2018/11/a-practo-theoretical-introduction-to-logic-programming/)  \u0026#x2014;a **colourful** read showing Prolog ≈ SQL.\n-   [ ] [Prolog Wikibook](https://en.wikibooks.org/wiki/Prolog) \u0026#x2014;slow-paced and cute\n-   [ ] [James Power's Prolog Tutorials](http://www.cs.nuim.ie/~jpower/Courses/Previous/PROLOG/)\n-   [X] [Introduction to Logic Programming Course](https://www3.risc.jku.at/education/courses/ws2009/logic-programming/) \u0026#x2014;Nice slides\n-   [ ] [Stackoverflow Prolog Questions](https://stackoverflow.com/questions/tagged/prolog)  \u0026#x2014;nifty FAQ stuff\n-   [ ] [99 Prolog Problems](https://sites.google.com/site/prologsite/prolog-problems)   \u0026#x2014;with solutions\n-   [ ] [The Power of Prolog](https://www.metalevel.at/prolog) \u0026#x2013;up to date tutorial, uses libraries ;-)\n-   [ ] [Backtracking](https://www.cis.upenn.edu/~matuszek/cit594-2012/Pages/backtracking.html)\n-   [ ] [Escape from Zurg: An Exercise in Logic Programming](http://web.engr.oregonstate.edu/~erwig/papers/Zurg_JFP04.pdf)\n-   [ ] [Efficient Prolog](https://www3.risc.jku.at/education/courses/ws2009/logic-programming/additional/Covington-Efficient-Prolog.pdf) \u0026#x2013;Practical tips\n-   [ ] [Use of Prolog for developing a new programming language](https://pdfs.semanticscholar.org/57d3/1ca47fa9688089b9b7e7c19c199aa03aff1e.pdf) \u0026#x2014;Erlang!\n-   [ ] [prolog :- tutorial](https://www.cpp.edu/~jrfisher/www/prolog_tutorial/pt_framer.html) \u0026#x2014;Example oriented\n-   [ ] [Learn Prolog Now!](http://www.learnprolognow.org/)  (or [here](http://cs.union.edu/~striegnk/learn-prolog-now/html/index.html)) \u0026#x2014;thorough, from basics to advanced\n-   [ ] [Real World Programming in SWI-Prolog](http://www.pathwayslms.com/swipltuts/index.html)\n-   [ ] [Adventures in Prolog](https://www.amzi.com/AdventureInProlog/a1start.php) \u0026#x2014;Amzi! inc.\n\n\u003ctable border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\"\u003e\n\n\n\u003ccolgroup\u003e\n\u003ccol  class=\"org-left\" /\u003e\n\u003c/colgroup\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"org-left\"\u003eAlso, here's [a nice set of 552 slides](https://people.eng.unimelb.edu.au/adrianrp/COMP90054/lectures/Prolog_Coding.pdf) ^\\_^\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falhassy%2Fprologcheatsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falhassy%2Fprologcheatsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falhassy%2Fprologcheatsheet/lists"}