diff options
author | Evert Heylen <evertheylen@gmail.com> | 2018-02-28 12:41:09 +0100 |
---|---|---|
committer | Pratik Karki <predatoramigo@gmail.com> | 2018-02-28 17:26:09 +0545 |
commit | eefc0a9c92f44655fd177920c9f1d40816afa119 (patch) | |
tree | 42bc56b61e941c09942b73e842c192e4e7b78044 /prolog.html.markdown | |
parent | 7d303e504235a68eca63ebb914872cdfea9469b6 (diff) |
[prolog/en] Corrected statement about unifying two free terms (#3033)
* Corrected statement about unifying two free terms
While the intricacies of unification would bring us too far, stating that assigning two free 'sides' is wrong. I tried to give a small description about how this works (without going into the details of occurrence checks or unification of more complex structures).
* Fixed indentation
* Replaced old style of structured comments
Diffstat (limited to 'prolog.html.markdown')
-rw-r--r-- | prolog.html.markdown | 116 |
1 files changed, 62 insertions, 54 deletions
diff --git a/prolog.html.markdown b/prolog.html.markdown index 4f3984c7..f7b55ac6 100644 --- a/prolog.html.markdown +++ b/prolog.html.markdown @@ -38,9 +38,9 @@ magicNumber(42). % predicate names must start with lower case letters. We can now use % interactive mode to ask if it is true for different values: -?- magicNumber(7). % True -?- magicNumber(8). % False -?- magicNumber(9). % True +?- magicNumber(7). % True +?- magicNumber(8). % False +?- magicNumber(9). % True % Some older Prologs may display "Yes" and "No" instead of True and % False. @@ -50,7 +50,7 @@ magicNumber(42). % starting with a capital letter is a variable in Prolog. ?- magicNumber(Presto). % Presto = 7 ; - % Presto = 9 ; + % Presto = 9 ; % Presto = 42. % Prolog makes magicNumber true by assigning one of the valid numbers to @@ -66,26 +66,33 @@ magicNumber(42). % follows: % If both sides are bound (ie, defined), check equality. % If one side is free (ie, undefined), assign to match the other side. -% If both sides are free, abort because this can't be resolved. +% If both sides are free, the assignment is remembered. With some luck, +% one of the two sides will eventually be bound, but this isn't +% necessary. +% % The = sign in Prolog represents unification, so: ?- 2 = 3. % False - equality test -?- X = 3. % X = 3 - assignment -?- X = 2, X = Y. % X = Y = 2 - two assignments +?- X = 3. % X = 3 - assignment +?- X = 2, X = Y. % X = Y = 2 - two assignments % Note Y is assigned to, even though it is % on the right hand side, because it is free ?- X = 3, X = 2. % False - % First acts as assignment and binds X=3 - % Second acts as equality because X is bound + % First acts as assignment and binds X=3 + % Second acts as equality because X is bound % Since 3 does not equal 2, gives False % Thus in Prolog variables are immutable ?- X = 3+2. % X = 3+2 - unification can't do arithmetic ?- X is 3+2. % X = 5 - "is" does arithmetic. -?- 5 = X+2. % This is why = can't do arithmetic - +?- 5 = X+2. % This is why = can't do arithmetic - % because Prolog can't solve equations ?- 5 is X+2. % Error. Unlike =, the right hand side of IS % must always be bound, thus guaranteeing % no attempt to solve an equation. +?- X = Y, X = 2, Z is Y + 3. % X = Y, Y = 2, Z = 5. + % X = Y are both free, so Prolog remembers + % it. Therefore assigning X will also + % assign Y. % Any unification, and thus any predicate in Prolog, can either: % Succeed (return True) without changing anything, @@ -101,11 +108,11 @@ magicNumber(42). % example, Prolog has a built in predicate plus which represents % arithmetic addition but can reverse simple additions. -?- plus(1, 2, 3). % True +?- plus(1, 2, 3). % True ?- plus(1, 2, X). % X = 3 because 1+2 = X. -?- plus(1, X, 3). % X = 2 because 1+X = 3. -?- plus(X, 2, 3). % X = 1 because X+2 = 3. -?- plus(X, 5, Y). % Error - although this could be solved, +?- plus(1, X, 3). % X = 2 because 1+X = 3. +?- plus(X, 2, 3). % X = 1 because X+2 = 3. +?- plus(X, 5, Y). % Error - although this could be solved, % the number of solutions is infinite, % which most predicates try to avoid. @@ -129,9 +136,9 @@ magicNumber(42). ?- print("Hello"). % "Hello" true. ?- X = 2, print(X). % 2 true. -?- X = 2, print(X), X = 3. % 2 false - print happens immediately when - % it is encountered, even though the overall - % compound goal fails (because 2 != 3, +?- X = 2, print(X), X = 3. % 2 false - print happens immediately when + % it is encountered, even though the overall + % compound goal fails (because 2 != 3, % see the example above). % By using Print we can see what actually happens when we give a @@ -156,7 +163,7 @@ magicNumber(42). % the interactive prompt by pressing ;, for example: ?- magicNumber(X), print(X), X > 8. % 7 9 X = 9 ; - % 42 X = 42. + % 42 X = 42. % As you saw above we can define our own simple predicates as facts. % More complex predicates are defined as rules, like this: @@ -168,7 +175,7 @@ nearby(X,Y) :- Y is X-1. % nearby(X,Y) is true if Y is X plus or minus 1. % However this predicate could be improved. Here's why: -?- nearby(2,3). % True ; False. +?- nearby(2,3). % True ; False. % Because we have three possible definitions, Prolog sees this as 3 % possibilities. X = Y fails, so Y is X+1 is then tried and succeeds, % giving the True answer. But Prolog still remembers there are more @@ -177,11 +184,11 @@ nearby(X,Y) :- Y is X-1. % the option of rejecting the True answer, which doesn't make a whole % lot of sense. -?- nearby(4, X). % X = 4 ; - % X = 5 ; - % X = 3. Great, this works -?- nearby(X, 4). % X = 4 ; - % error +?- nearby(4, X). % X = 4 ; + % X = 5 ; + % X = 3. Great, this works +?- nearby(X, 4). % X = 4 ; + % error % After rejecting X = 4 prolog backtracks and tries "Y is X+1" which is % "4 is X+1" after substitution of parameters. But as we know from above % "is" requires its argument to be fully instantiated and it is not, so @@ -195,10 +202,10 @@ nearbychk(X,Y) :- Y is X+1, !. nearbychk(X,Y) :- Y is X-1. % This solves the first problem: -?- nearbychk(2,3). % True. +?- nearbychk(2,3). % True. % But unfortunately it has consequences: -?- nearbychk(2,X). % X = 2. +?- nearbychk(2,X). % X = 2. % Because Prolog cannot backtrack past the cut after X = Y, it cannot % try the possibilities "Y is X+1" and "Y is X-1", so it only generates % one solution when there should be 3. @@ -230,9 +237,9 @@ nearby3(X,Y) :- nearby2(X,Y). % Here is the structured comment declaration for nearby3: -%% nearby3(+X:Int, +Y:Int) is semideterministic. -%% nearby3(+X:Int, -Y:Int) is multi. -%% nearby3(-X:Int, +Y:Int) is multi. +%! nearby3(+X:Int, +Y:Int) is semideterministic. +%! nearby3(+X:Int, -Y:Int) is multi. +%! nearby3(-X:Int, +Y:Int) is multi. % For each variable we list a type. The + or - before the variable name % indicates if the parameter is bound (+) or free (-). The word after @@ -250,13 +257,13 @@ nearby3(X,Y) :- nearby2(X,Y). % An unusual feature of Prolog is its support for atoms. Atoms are % essentially members of an enumerated type that are created on demand % whenever an unquoted non variable value is used. For example: -character(batman). % Creates atom value batman -character(robin). % Creates atom value robin -character(joker). % Creates atom value joker -character(darthVader). % Creates atom value darthVader -?- batman = batman. % True - Once created value is reused -?- batman = batMan. % False - atoms are case sensitive -?- batman = darthVader. % False - atoms are distinct +character(batman). % Creates atom value batman +character(robin). % Creates atom value robin +character(joker). % Creates atom value joker +character(darthVader). % Creates atom value darthVader +?- batman = batman. % True - Once created value is reused +?- batman = batMan. % False - atoms are case sensitive +?- batman = darthVader. % False - atoms are distinct % Atoms are popular in examples but were created on the assumption that % Prolog would be used interactively by end users - they are less @@ -267,54 +274,55 @@ character(darthVader). % Creates atom value darthVader % Note that below, writeln is used instead of print because print is % intended for debugging. -%% countTo(+X:Int) is deterministic. -%% countUpTo(+Value:Int, +Limit:Int) is deterministic. +%! countTo(+X:Int) is deterministic. +%! countUpTo(+Value:Int, +Limit:Int) is deterministic. countTo(X) :- countUpTo(1,X). countUpTo(Value, Limit) :- Value = Limit, writeln(Value), !. countUpTo(Value, Limit) :- Value \= Limit, writeln(Value), - NextValue is Value+1, - countUpTo(NextValue, Limit). + NextValue is Value+1, + countUpTo(NextValue, Limit). -?- countTo(10). % Outputs 1 to 10 +?- countTo(10). % Outputs 1 to 10 % Note the use of multiple declarations in countUpTo to create an % IF test. If Value = Limit fails the second declaration is run. % There is also a more elegant syntax. -%% countUpTo2(+Value:Int, +Limit:Int) is deterministic. +%! countUpTo2(+Value:Int, +Limit:Int) is deterministic. countUpTo2(Value, Limit) :- writeln(Value), - Value = Limit -> true ; ( - NextValue is Value+1, - countUpTo2(NextValue, Limit)). + Value = Limit -> true ; ( + NextValue is Value+1, + countUpTo2(NextValue, Limit)). -?- countUpTo2(1,10). % Outputs 1 to 10 +?- countUpTo2(1,10). % Outputs 1 to 10 % If a predicate returns multiple times it is often useful to loop % through all the values it returns. Older Prologs used a hideous syntax % called a "failure-driven loop" to do this, but newer ones use a higher % order function. -%% countTo2(+X:Int) is deterministic. +%! countTo2(+X:Int) is deterministic. countTo2(X) :- forall(between(1,X,Y),writeln(Y)). -?- countTo2(10). % Outputs 1 to 10 +?- countTo2(10). % Outputs 1 to 10 % Lists are given in square brackets. Use memberchk to check membership. % A group is safe if it doesn't include Joker or does include Batman. -%% safe(Group:list(atom)) is deterministic. + +%! safe(Group:list(atom)) is deterministic. safe(Group) :- memberchk(joker, Group) -> memberchk(batman, Group) ; true. -?- safe([robin]). % True -?- safe([joker]). % False -?- safe([joker, batman]). % True +?- safe([robin]). % True +?- safe([joker]). % False +?- safe([joker, batman]). % True % The member predicate works like memberchk if both arguments are bound, % but can accept free variables and thus can be used to loop through % lists. -?- member(X, [1,2,3]). % X = 1 ; X = 2 ; X = 3 . +?- member(X, [1,2,3]). % X = 1 ; X = 2 ; X = 3 . ?- forall(member(X,[1,2,3]), - (Y is X+1, writeln(Y))). % 2 3 4 + (Y is X+1, writeln(Y))). % 2 3 4 % The maplist function can be used to generate lists based on other % lists. Note that the output list is a free variable, causing an |