diff --git a/logic_programming/2_IntroProlog.ipynb b/logic_programming/2_IntroProlog.ipynb index ffca183a0452fce1ff804f40ff0b2b6671e9642a..06d4722851d13643df61b8c7518cb74720d6e09a 100644 --- a/logic_programming/2_IntroProlog.ipynb +++ b/logic_programming/2_IntroProlog.ipynb @@ -786,6 +786,15 @@ "?- edge(A,B,C)." ] }, + { + "cell_type": "markdown", + "id": "c137912e", + "metadata": {}, + "source": [ + "By calling jupyter:print_transition_graph(PredSpec, FromIdx, ToIdx, LabelIdx),\n", + "a transition graph can be created (FromIdx is the number of argument specifying the origin, ToIdx the destination and LabelIdx the label)." + ] + }, { "cell_type": "code", "execution_count": 68, @@ -1213,64 +1222,14 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 44, "id": "12f78859", "metadata": { "vscode": { "languageId": "prolog" } }, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - " <style>\n", - " details {\n", - " font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n", - " }\n", - "\n", - " details > summary {\n", - " cursor: pointer;\n", - " }\n", - " </style>\n", - " <details><summary>Previously defined clauses of user:edge/2 were retracted (click to expand)</summary><pre>:- dynamic edge/2.\n", - "\n", - "edge(a, b).\n", - "edge(a, c).\n", - "edge(b, d).\n", - "edge(c, d).\n", - "edge(d, e).\n", - "edge(f, g).\n", - "</pre></details>" - ], - "text/plain": [ - "Previously defined clauses of user:edge/2 were retracted:\n", - ":- dynamic edge/2.\n", - "\n", - "edge(a, b).\n", - "edge(a, c).\n", - "edge(b, d).\n", - "edge(c, d).\n", - "edge(d, e).\n", - "edge(f, g).\n" - ] - }, - "metadata": { - "application/json": {} - }, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "% Asserting clauses for user:edge/2\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "edge(a,b). edge(a,c).\n", "edge(b,d). edge(c,d).\n", @@ -1288,7 +1247,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 45, "id": "99bfae95", "metadata": { "vscode": { @@ -1302,7 +1261,7 @@ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n", "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n", " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n", - "<!-- Generated by graphviz version 6.0.1 (20220911.1526)\n", + "<!-- Generated by graphviz version 10.0.1 (20240210.2158)\n", " -->\n", "<!-- Pages: 1 -->\n", "<svg width=\"206pt\" height=\"260pt\"\n", @@ -1313,79 +1272,79 @@ "<g id=\"node1\" class=\"node\">\n", "<title>a</title>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"63\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"63\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">a</text>\n", + "<text text-anchor=\"middle\" x=\"63\" y=\"-228.95\" font-family=\"Times,serif\" font-size=\"14.00\">a</text>\n", "</g>\n", "<!-- b -->\n", "<g id=\"node2\" class=\"node\">\n", "<title>b</title>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"27\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">b</text>\n", + "<text text-anchor=\"middle\" x=\"27\" y=\"-156.95\" font-family=\"Times,serif\" font-size=\"14.00\">b</text>\n", "</g>\n", "<!-- a->b -->\n", "<g id=\"edge1\" class=\"edge\">\n", "<title>a->b</title>\n", - "<path fill=\"none\" stroke=\"black\" d=\"M54.65,-216.76C50.29,-208.28 44.85,-197.71 39.96,-188.2\"/>\n", - "<polygon fill=\"black\" stroke=\"black\" points=\"42.99,-186.44 35.3,-179.15 36.77,-189.64 42.99,-186.44\"/>\n", + "<path fill=\"none\" stroke=\"black\" d=\"M54.65,-216.76C50.42,-208.55 45.19,-198.37 40.42,-189.09\"/>\n", + "<polygon fill=\"black\" stroke=\"black\" points=\"43.68,-187.79 36,-180.49 37.46,-190.99 43.68,-187.79\"/>\n", "</g>\n", "<!-- c -->\n", "<g id=\"node3\" class=\"node\">\n", "<title>c</title>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"99\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">c</text>\n", + "<text text-anchor=\"middle\" x=\"99\" y=\"-156.95\" font-family=\"Times,serif\" font-size=\"14.00\">c</text>\n", "</g>\n", "<!-- a->c -->\n", "<g id=\"edge2\" class=\"edge\">\n", "<title>a->c</title>\n", - "<path fill=\"none\" stroke=\"black\" d=\"M71.35,-216.76C75.71,-208.28 81.15,-197.71 86.04,-188.2\"/>\n", - "<polygon fill=\"black\" stroke=\"black\" points=\"89.23,-189.64 90.7,-179.15 83.01,-186.44 89.23,-189.64\"/>\n", + "<path fill=\"none\" stroke=\"black\" d=\"M71.35,-216.76C75.58,-208.55 80.81,-198.37 85.58,-189.09\"/>\n", + "<polygon fill=\"black\" stroke=\"black\" points=\"88.54,-190.99 90,-180.49 82.32,-187.79 88.54,-190.99\"/>\n", "</g>\n", "<!-- d -->\n", "<g id=\"node4\" class=\"node\">\n", "<title>d</title>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"63\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"63\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">d</text>\n", + "<text text-anchor=\"middle\" x=\"63\" y=\"-84.95\" font-family=\"Times,serif\" font-size=\"14.00\">d</text>\n", "</g>\n", "<!-- b->d -->\n", "<g id=\"edge3\" class=\"edge\">\n", "<title>b->d</title>\n", - "<path fill=\"none\" stroke=\"black\" d=\"M35.35,-144.76C39.71,-136.28 45.15,-125.71 50.04,-116.2\"/>\n", - "<polygon fill=\"black\" stroke=\"black\" points=\"53.23,-117.64 54.7,-107.15 47.01,-114.44 53.23,-117.64\"/>\n", + "<path fill=\"none\" stroke=\"black\" d=\"M35.35,-144.76C39.58,-136.55 44.81,-126.37 49.58,-117.09\"/>\n", + "<polygon fill=\"black\" stroke=\"black\" points=\"52.54,-118.99 54,-108.49 46.32,-115.79 52.54,-118.99\"/>\n", "</g>\n", "<!-- c->d -->\n", "<g id=\"edge4\" class=\"edge\">\n", "<title>c->d</title>\n", - "<path fill=\"none\" stroke=\"black\" d=\"M90.65,-144.76C86.29,-136.28 80.85,-125.71 75.96,-116.2\"/>\n", - "<polygon fill=\"black\" stroke=\"black\" points=\"78.99,-114.44 71.3,-107.15 72.77,-117.64 78.99,-114.44\"/>\n", + "<path fill=\"none\" stroke=\"black\" d=\"M90.65,-144.76C86.42,-136.55 81.19,-126.37 76.42,-117.09\"/>\n", + "<polygon fill=\"black\" stroke=\"black\" points=\"79.68,-115.79 72,-108.49 73.46,-118.99 79.68,-115.79\"/>\n", "</g>\n", "<!-- e -->\n", "<g id=\"node5\" class=\"node\">\n", "<title>e</title>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"63\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"63\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">e</text>\n", + "<text text-anchor=\"middle\" x=\"63\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">e</text>\n", "</g>\n", "<!-- d->e -->\n", "<g id=\"edge5\" class=\"edge\">\n", "<title>d->e</title>\n", - "<path fill=\"none\" stroke=\"black\" d=\"M63,-71.7C63,-63.98 63,-54.71 63,-46.11\"/>\n", - "<polygon fill=\"black\" stroke=\"black\" points=\"66.5,-46.1 63,-36.1 59.5,-46.1 66.5,-46.1\"/>\n", + "<path fill=\"none\" stroke=\"black\" d=\"M63,-71.7C63,-64.41 63,-55.73 63,-47.54\"/>\n", + "<polygon fill=\"black\" stroke=\"black\" points=\"66.5,-47.62 63,-37.62 59.5,-47.62 66.5,-47.62\"/>\n", "</g>\n", "<!-- f -->\n", "<g id=\"node6\" class=\"node\">\n", "<title>f</title>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"171\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">f</text>\n", + "<text text-anchor=\"middle\" x=\"171\" y=\"-228.95\" font-family=\"Times,serif\" font-size=\"14.00\">f</text>\n", "</g>\n", "<!-- g -->\n", "<g id=\"node7\" class=\"node\">\n", "<title>g</title>\n", "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"171\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">g</text>\n", + "<text text-anchor=\"middle\" x=\"171\" y=\"-156.95\" font-family=\"Times,serif\" font-size=\"14.00\">g</text>\n", "</g>\n", "<!-- f->g -->\n", "<g id=\"edge6\" class=\"edge\">\n", "<title>f->g</title>\n", - "<path fill=\"none\" stroke=\"black\" d=\"M171,-215.7C171,-207.98 171,-198.71 171,-190.11\"/>\n", - "<polygon fill=\"black\" stroke=\"black\" points=\"174.5,-190.1 171,-180.1 167.5,-190.1 174.5,-190.1\"/>\n", + "<path fill=\"none\" stroke=\"black\" d=\"M171,-215.7C171,-208.41 171,-199.73 171,-191.54\"/>\n", + "<polygon fill=\"black\" stroke=\"black\" points=\"174.5,-191.62 171,-181.62 167.5,-191.62 174.5,-191.62\"/>\n", "</g>\n", "</g>\n", "</svg>\n" @@ -1418,6 +1377,28 @@ "jupyter:print_transition_graph(edge/2, 1, 2,0)." ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "b400c8fa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[1;31mERROR: call/1: Unknown procedure: jupyter:print_transition_graph/1\n", + "ERROR: However, there are definitions for:\n", + "ERROR: jupyter:print_transition_graph/4\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "jupyter:print_transition_graph(edge/2)." + ] + }, { "cell_type": "code", "execution_count": 75, @@ -2191,126 +2172,321 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 13, "id": "d4664fd8", "metadata": { "vscode": { "languageId": "prolog" } }, + "outputs": [], + "source": [ + "\n", + "construct(Name,Department,employe(Name,Department)).\n", + "\n", + "get_name(employe(Name,_),Name).\n", + "get_dept(employe(_,Dept),Dept)." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "08715fa2", + "metadata": { + "vscode": { + "languageId": "prolog" + } + }, "outputs": [ { "data": { - "text/html": [ - "\n", - " <style>\n", - " details {\n", - " font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n", - " }\n", - "\n", - " details > summary {\n", - " cursor: pointer;\n", - " }\n", - " </style>\n", - " <details><summary>Previously defined clauses of user:construct/3 were retracted (click to expand)</summary><pre>:- dynamic construct/3.\n", - "\n", - "construct(A, B, employe(A, B)).\n", - "</pre></details>" - ], "text/plain": [ - "Previously defined clauses of user:construct/3 were retracted:\n", - ":- dynamic construct/3.\n", - "\n", - "construct(A, B, employe(A, B)).\n" + "\u001b[1mE1 = employe(peter,cs),\n", + "E2 = employe(mary,cs),\n", + "N1 = peter,\n", + "D2 = cs" ] }, - "metadata": { - "application/json": {} - }, + "metadata": {}, "output_type": "display_data" - }, + } + ], + "source": [ + "?- construct(peter,cs,E1), construct(mary,cs,E2), get_name(E1,N1), get_dept(E2,D2)." + ] + }, + { + "cell_type": "markdown", + "id": "43452d97", + "metadata": {}, + "source": [ + "Let us work out a small database example using such compound terms for data abstraction:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "e9ff8860", + "metadata": {}, + "outputs": [], + "source": [ + "% Facts for courses with time slot and location:\n", + "course(logic_programming,time(tuesday,1430,1600),location(25,'5F')).\n", + "course(sks,time(monday,1430,1600),location(25,'5G')).\n", + "course(drones,time(thursday,1430,1600),location(25,'12.O2.55')).\n", + "course(navigating_tomorrow,time(thursday,1430,1600),location(25,'12.O2.21')).\n", + "% separate facts about which programme the courses belong to (can be multiple):\n", + "programme(logic_programming,bachelor_cs).\n", + "programme(logic_programming,master_dsai).\n", + "programme(sks,master_cs).\n", + "programme(navigating_tomorrow,bachelor_cs).\n" + ] + }, + { + "cell_type": "markdown", + "id": "3dc100cb", + "metadata": {}, + "source": [ + "Let us try and write a predicate for:\n", + "- which courses take place on a particular day\n", + "- which courses take place in a particular building (e.g., 25)\n", + "- which courses are available for multiple programmes\n", + "- which courses are in conflict (time-wise)\n", + "- on which days there are courses a given programme (e.g., bachelor_cs)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fbed4b05", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f506936", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "c34b9d8c", + "metadata": {}, + "source": [ + "Here is a solution. You will see that the compound term encoding of times and buildings\n", + "has some advantages and drawbacks over a flatter representation such as course/6 with 6 arguments:\n", + "```\n", + "course(logic_programming,tuesday,1430,1600,25,'5F').\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "74a9e660", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "day(Lect,Day) :- course(Lect,time(Day,_,_),_).\n", + "building(Lect,Bldg) :- course(Lect,_,location(Bldg,_)).\n", + "multi(Lect) :- course(Lect,_,_), programme(Lect,P1), programme(Lect,P2), P1\\=P2.\n", + "conflict(L1,L2) :- course(L1,T,_), course(L2,T,_), L1\\=L2.\n", + "lecture_day(Day,Progr) :- course(L1,time(Day,_,_),_), programme(L1,Progr)." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "3cddfd08", + "metadata": {}, + "outputs": [ { "data": { "text/plain": [ - "% Asserting clauses for user:construct/3\n" + "\u001b[1mL = logic_programming" ] }, "metadata": {}, "output_type": "display_data" - }, + } + ], + "source": [ + "?- multi(L)." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "9271f0d7", + "metadata": {}, + "outputs": [ { "data": { - "text/html": [ - "\n", - " <style>\n", - " details {\n", - " font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n", - " }\n", - "\n", - " details > summary {\n", - " cursor: pointer;\n", - " }\n", - " </style>\n", - " <details><summary>Previously defined clauses of user:get_name/2 were retracted (click to expand)</summary><pre>:- dynamic get_name/2.\n", - "\n", - "get_name(employe(A, _), A).\n", - "</pre></details>" - ], "text/plain": [ - "Previously defined clauses of user:get_name/2 were retracted:\n", - ":- dynamic get_name/2.\n", - "\n", - "get_name(employe(A, _), A).\n" + "\u001b[1mX = drones,\n", + "Y = navigating_tomorrow" ] }, - "metadata": { - "application/json": {} - }, + "metadata": {}, "output_type": "display_data" - }, + } + ], + "source": [ + "?- conflict(X,Y)." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "d7b8619e", + "metadata": {}, + "outputs": [ { "data": { "text/plain": [ - "% Asserting clauses for user:get_name/2\n" + "\u001b[1mL = [tuesday,thursday]" ] }, "metadata": {}, "output_type": "display_data" - }, + } + ], + "source": [ + "?- findall(D,lecture_day(D,bachelor_cs),L)." + ] + }, + { + "cell_type": "markdown", + "id": "e2ed5de7", + "metadata": {}, + "source": [ + "## Peano Arithmetic\n", + "\n", + "The arguments to a functor can in term also make use of a functor.\n", + "\n", + "We can also use functors of arity 1. (Functors of arity 0 are simply constants, i.e., atoms in Prolog terminology.)\n", + "This can be used to represent natural numbers:\n", + "- we can represent zero using the atom `zero/0`\n", + "- we can represent the successor of a number using a functor `s/1` \n", + "\n", + "Thus the number 1 is represented by the term `s(zero)` and the number 2 by `s(s(zero))`.\n", + "\n", + "How could one write predicates to check if a term is a valid natural number in that representation?\n", + "E.g., `s(zero)` is valid, `s(a)` is not.\n", + "How could one write addition and multiplication predicate to add or multiply two numbers?\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d1a7bf2", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1735fe4c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "dbc89f40", + "metadata": {}, + "source": [ + "A possible solution is this one.\n", + "This is also called Peano arithmetic. Note, that contrary to built-in arithmetic (using is/2), these predicates are reversible" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "d44c70af", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "\n", + "\n", + "nat(zero).\n", + "nat(s(X)) :- nat(X).\n", + "\n", + "plus(zero,X,X).\n", + "plus(s(X),Y,s(Z)) :- plus(X,Y,Z).\n", + "\n", + "mult(zero,_,zero).\n", + "mult(s(X),Y,Z) :- mult(X,Y,XY), plus(Y,XY,Z). % (x+1)*y = x*y + y\n", + "\n", + "exp(zero,s(_),zero).\n", + "exp(s(_),zero,s(zero)).\n", + "exp(Y,s(X),Z) :- exp(Y,X,YX), mult(YX,Y,Z)." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "6e96b7aa", + "metadata": {}, + "outputs": [ { "data": { - "text/html": [ - "\n", - " <style>\n", - " details {\n", - " font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 13px;\n", - " }\n", - "\n", - " details > summary {\n", - " cursor: pointer;\n", - " }\n", - " </style>\n", - " <details><summary>Previously defined clauses of user:get_dept/2 were retracted (click to expand)</summary><pre>:- dynamic get_dept/2.\n", - "\n", - "get_dept(employe(_, A), A).\n", - "</pre></details>" - ], "text/plain": [ - "Previously defined clauses of user:get_dept/2 were retracted:\n", - ":- dynamic get_dept/2.\n", - "\n", - "get_dept(employe(_, A), A).\n" + "\u001b[1mR = s(s(s(zero)))" ] }, - "metadata": { - "application/json": {} + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "?-plus(s(s(zero)),s(zero),R)." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "d119214f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[1mR = s(s(s(s(s(s(zero))))))" + ] }, + "metadata": {}, "output_type": "display_data" - }, + } + ], + "source": [ + "?-mult(s(s(zero)),s(s(s(zero))),R)." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "b3c9b644", + "metadata": {}, + "outputs": [ { "data": { "text/plain": [ - "% Asserting clauses for user:get_dept/2\n" + "\u001b[1mR = s(s(s(s(s(s(s(s(zero))))))))" ] }, "metadata": {}, @@ -2318,30 +2494,39 @@ } ], "source": [ - "\n", - "construct(Name,Department,employe(Name,Department)).\n", - "\n", - "get_name(employe(Name,_),Name).\n", - "get_dept(employe(_,Dept),Dept)." + "?-exp(s(s(zero)),s(s(s(zero))),R)." ] }, { "cell_type": "code", - "execution_count": 87, - "id": "08715fa2", - "metadata": { - "vscode": { - "languageId": "prolog" + "execution_count": 42, + "id": "e61cc47b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[1mX = s(zero)" + ] + }, + "metadata": {}, + "output_type": "display_data" } - }, + ], + "source": [ + "?-plus(X,s(zero),s(s(zero)))." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "747d23d1", + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\u001b[1mE1 = employe(a,cs),\n", - "E2 = employe(b,cs),\n", - "N1 = a,\n", - "D2 = cs" + "\u001b[1mX = s(s(zero))" ] }, "metadata": {}, @@ -2349,21 +2534,24 @@ } ], "source": [ - "?- construct(a,cs,E1), construct(b,cs,E2), get_name(E1,N1), get_dept(E2,D2)." + "?-mult(X,s(zero),s(s(zero)))." ] }, { "cell_type": "markdown", - "id": "e2ed5de7", + "id": "15942ef6", "metadata": {}, "source": [ - "The arguments to a functor can in term also make use of a functor.\n", + "## Recursive Data Structures\n", + "\n", + "Compound terms can be used the represent complex data structures, as will see below.\n", + "First, think on how one could represent a list of objects, say a list of length 2 containing `a` and `b`.\n", "\n", - "One could thus for example represent a list in Prolog by using\n", + "One could for example represent a list in Prolog by using\n", "a functor `cons/2` to denote a non-empty list and `nil/0` to denote\n", "an empty list.\n", - "Note that a functor of arity 0 is simply a constant (aka atom in Prolog).\n", - "So a list of length two with a and b as elements is represented as follows:" + "(Remember, a functor of arity 0 is simply a constant (aka atom in Prolog).)\n", + "So a list of length two with a and b as elements can be represented as follows:" ] }, { @@ -2826,6 +3014,30 @@ "?- last0(X,cons(a,cons(b,nil)))." ] }, + { + "cell_type": "markdown", + "id": "34c38129", + "metadata": {}, + "source": [ + "Exercise: write predicates prefix/2 and suffix/2 which is true if the first argument is a prefix or suffix of the second one." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a65d023", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df88c4bd", + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "id": "5f251e4d", @@ -2839,7 +3051,10 @@ "- the left sub-tree\n", "- the information at the root of the tree\n", "- the right sub-tree\n", - "We also need the empty tree, which we represent by `nil`." + "We also need the empty tree, which we represent by `nil`.\n", + "\n", + "For example, how would you represent this tree:\n", + "" ] }, { @@ -2866,6 +3081,14 @@ "?- Mytree = tree( tree(nil,a,nil), b, tree(nil,c,tree(nil,d,nil)))." ] }, + { + "cell_type": "markdown", + "id": "8ac0d99f", + "metadata": {}, + "source": [ + "Let us now try to write a predicate which reverses (mirrors) the tree, swapping left and right children:" + ] + }, { "cell_type": "code", "execution_count": 104, diff --git a/logic_programming/img/simple_tree.png b/logic_programming/img/simple_tree.png new file mode 100644 index 0000000000000000000000000000000000000000..6ae0a1bc2aabb33e824d3b1f27e3cd129f6dda65 Binary files /dev/null and b/logic_programming/img/simple_tree.png differ