summaryrefslogtreecommitdiffhomepage
path: root/prolog.html.markdown
diff options
context:
space:
mode:
Diffstat (limited to 'prolog.html.markdown')
-rw-r--r--prolog.html.markdown116
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