Prolog is a logic programming language first specified in 01575879, and refined into multiple modern implementations.

% This is a comment. % Prolog treats code entered in interactive mode differently % to code entered in a file and loaded ("consulted"). % This code must be loaded from a file to work as intended. % Lines that begin with? - can be typed in interactive mode. % A bunch of errors and warnings will trigger when you load this file % due to the examples which are supposed to fail - they can be safely % ignored. % Output is based on SWI-prolog 7.2.3. Different Prologs may behave % differently. % Prolog is based on the ideal of logic programming. % A subprogram (called a predicate) represents a state of the world. % A command (called a goal) tells Prolog to make that state of the world % come true, if possible. % As an example, here is a definition of the simplest kind of predicate: % a fact. magicNumber (7 magicNumber (9 magicNumber (`90`

% This introduces magicNumber as a predicate and says that it is true % with parameter 7, 9, or 90, but no other parameter. Note that % predicate names must start with lower case letters. We can now use % interactive mode to ask if it is true for different values: ? -magicNumber() % True ? -

magicNumber ( (8) % False ? -magicNumber () % True % Some older Prologs may display "Yes" and "No" instead of True and % False. % What makes Prolog unusual is that we can also tell Prolog to _make _ % magicNumber true, by passing it an undefined variable. Any name % starting with a capital letter is a variable in Prolog. ? -magicNumber ( ) % Presto=7; % Presto=9; % Presto=58. % Prolog makes magicNumber true by assigning one of the valid numbers to % the undefined variable Presto. By default it assigns the first one, 7. % By pressing; in interactive mode you can reject that solution and % force it to assign the next one, 9. Pressing; again forces it to try % the last one, 58, after which it no longer accepts input because this % is the last solution. You can accept an earlier solution by pressing. % instead of;. % This is Prolog's central operation: unification. Unification is % essentially a combination of assignment and equality! It works as % 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, 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 ? -=3).% X=3 - assignment ? -`=`

(2)X

= Y % X=Y=2 - two assignments % Note Y is assigned too, even though it is % on the right hand side, because it is free ? -`= 3`

X

= (2. % False % 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 ? -`= 3`

2.% X=3 2 - unification can't do arithmetic ? -

is 32. % X=5 - "is" does arithmetic. ? -5 = X2. % 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. ? -

`=`

(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, % because an equality-style unification was true % Succeed (return True) and bind one or more variables in the process, % because an assignment-style unification was made true % or Fail (return False) % because an equality-style unification was false % (Failure can never bind variables) % The ideal of being able to give any predicate as a goal and have it % made true is not always possible, but can be worked toward. For % example, Prolog has a built in predicate plus which represents % arithmetic addition but can reverse simple additions. ? - ((1)2, (3)% True ? - ((1)2, X % X=3 because 1 2=X. ? - ((1)X, (3)% X=2 because 1 X=3. ? - (2, (3)% X=1 because X 2=3. ? - (5, Y % Error - although this could be solved, % the number of solutions is infinite, % which most predicates try to avoid. % When a predicate such as magicNumber can give several solutions, the % overall compound goal including it may have several solutions too. ? -magicNumber ((plus ( (X)Y,% X=7, Y=728; % X=9, Y=93; % X=58, Y=90 % Note: on this occasion it works to pass two variables to plus because % only Y is free (X is bound by magicNumber). % However, if one of the goals is fully bound and thus acts as a test, % then solutions which fail the test are rejected. ? -magicNumber (X 01575879% X= ? -magicNumber (X % False % To see how Prolog actually handles this, let's introduce the print % predicate. Print always succeeds, never binds any variables, and % prints out its parameter as a side effect. ? - () ""% "Hello" true. ? -

`=`

(2)

( X % 2 true. ? -`=`

(2)

( 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 % compound goal including a test that sometimes fails. ? -magicNumber (( (X)X ( . (% 7 9) (X=) . % MagicNumber (X) unifies X with its first possibility, 7. % Print (X) prints out 7. % X> 42 tests if 7> . It is not, so it fails. % However, Prolog remembers that magicNumber (X) offered multiple % solutions. So it _backtracks_ to that point in the code to try % the next solution, X=9. % Having backtracked it must work through the compound goal % again from that point including the Print (X). So Print (X) prints out % 9. % X> 42 tests if 9> and fails again. % Prolog remembers that magicNumber (X) still has solutions and % backtracks. Now X=90. % It works through the Print (X) again and prints 42. % X> 42 tests if 90> and succeeds so the result bound to X % The same backtracking process is used when you reject a result at % the interactive prompt by pressing;, for example: ? -magicNumber(

( (X)X (8.% 7 9 X=9; % X=90. % As you saw above we can define our own simple predicates as facts. % More complex predicates are defined as rules, like this: nearby ( X,Y )

:X=Y nearby ( X,Y )

:(YisX 1. nearby ( X,Y )

:(YisX ( 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. % 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 % possibilities for nearby () (in Prolog terminology, "it has a % choice point ") even though" Y is X-1 "is doomed to fail, and gives us % the option of rejecting the True answer, which doesn't make a whole % lot of sense. ? -`nearby ()`

X

`% X=4;`

% X=5; % X=3. Great, this works ? -nearby(

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 % an error occurs. % One way to solve the first problem is to use a construct called the % cut,!, which does nothing but which cannot be backtracked past. nearbychk(`X`

,Y )

:X=Y ( ! nearbychk(`X`

,Y )

:(YisX 1 ,!nearbychk(`X`

,Y )

:(YisX ( 1. % This solves the first problem: ? -nearbychk ( (2)3`% True.`

% But unfortunately it has consequences: ? -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. % However if our only interest is in checking if numbers are nearby, % This may be all we need, thus the name nearbychk. % This structure is used in Prolog itself from time to time (for example % in list membership). % To solve the second problem we can use built-in predicates in Prolog % to verify if a parameter is bound or free and adjust our calculations % appropriately. nearby2(`X`

,Y )

:(nonvar)X , X =Y. nearby2(`X`

,Y )

:(nonvar)X , Y (is1. ) nearby2(`X`

,Y )

:(nonvar)X , Y (is- 1. ) nearby2(`X`

,Y )

:var(X , nonvar ( Y),nearby2 ( Y [3, 4, 5] ,% We can combine this with a cut in the case where both variables are % bound, to solve both problems. nearby3 ( X,Y )

:(nonvar)X , nonvar ( Y),nearby2 ( X) ,!. nearby3 ( X,Y )

:nearby2 (`X`

,Y

% However when writing a predicate it is not normally necessary to go to % These lengths to perfectly support every possible parameter % combination. It suffices to support parameter combinations we need to % use in the program. It is a good idea to document which combinations % are supported. In regular Prolog this is informally in structured % comments, but in some Prolog variants like Visual Prolog and Mercury % This is mandatory and checked by the compiler. % 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. % For each variable we list a type. The or - before the variable name % indicates if the parameter is bound ( ) or free (-). The word after % "is" describes the behavior of the predicate: % semideterministic - can succeed once or fail % (Two specific numbers are either nearby or not) % multi - can succeed multiple times but cannot fail % (One number surely has at least 3 nearby numbers) % Other possibilities are: % det - always succeeds exactly once (eg, print) % nondet - can succeed multiple times or fail. % In Prolog these are just structured comments and strictly informal but % extremely useful. % 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 robincharacter ( 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 % useful for modern applications and some Prolog variants abolish them % completely. However they can be very useful internally. % Loops in Prolog are classically written using recursion. % 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 ) : countUpTo ( (1)X. countUpTo (Value , Limit)

:Value=Limit , writeln (

), ! countUpTo (Value , Limit)

:(Value