Introduction
Welcome to SLP-PROLOG, the Logic Programming Language from Emulator.ca Systems.
In 1972, Alain Colmerauer and Philippe Roussel at the University of Aix-Marseille created a new kind of programming language. Instead of telling the computer how to solve a problem step by step, you could describe what the solution should look like, and let the computer figure out the rest. They called this language Prolog -- "Programming in Logic."
This was a profound shift in thinking about computation. Rather than writing procedures, you write facts and rules. Rather than looping through data, you ask questions and let Prolog search for answers. For problems involving relationships, pattern matching, and symbolic reasoning, Prolog offers an elegance that conventional languages cannot match.
SLP-PROLOG brings this distinctive approach to logic programming to your EC-TTY terminal. Whether you are exploring artificial intelligence concepts, building expert systems, or simply learning a different way to think about problems, Prolog will expand your understanding of what programming can be.
What Makes Prolog Different
In most programming languages, you write instructions: "First do this, then do that." In Prolog, you state facts: "Alex is Jamie's parent." You define rules: "X is a grandparent of Y if X is a parent of someone who is a parent of Y." Then you ask questions: "Who are Alex's grandchildren?"
Prolog searches through your facts and rules, trying different possibilities until it finds answers that satisfy your query. If there are multiple answers, it can find them all. This declarative style makes Prolog especially well-suited for:
- Database queries and relational reasoning - Ask questions about complex relationships
- Natural language processing - Parse and understand sentence structure
- Expert systems and decision support - Encode knowledge as rules, let Prolog draw conclusions
- Symbolic computation and theorem proving - Manipulate logical expressions
- Puzzles and constraint satisfaction problems - Describe the solution, let Prolog find it
Why Learn Prolog?
Even if you never use Prolog professionally, learning it will change how you think about programming. You will start to see problems differently - not as sequences of steps, but as relationships to be described. This perspective is valuable in any language.
And Prolog is fun. There is something deeply satisfying about describing a problem correctly and watching the computer deduce the answer. When your first recursive rule produces dozens of correct results from a handful of facts, you will understand why logicians and AI researchers fell in love with this language.
SLP-PROLOG aims toward ISO Prolog compatibility but currently implements a subset of the standard. See the "Current Implementation" section for details on what is supported. Programs may need adaptation when moving to other Prolog systems.
Current Implementation
SLP-PROLOG implements a core subset of Prolog suitable for learning logic programming fundamentals. This section clarifies what is currently supported.
SLP-PROLOG is a teaching implementation. Many standard Prolog predicates documented in textbooks are outside the current subset. Programs from other Prolog systems may need adaptation.
What Works
| Feature | Status | Notes |
|---|---|---|
| Facts and rules | Full support | Define with fact. or head :- body. |
| Queries | Full support | Interactive queries with ?- prompt |
| Unification | Full support | X = Y and pattern matching |
| Backtracking | Full support | All solutions enumerated automatically |
| Lists | Full support | [a, b, c] and `[H |
| Basic arithmetic | Supported | X is Expr with +, -, *, /, mod |
| Arithmetic comparison | Supported | <, >, =<, >=, =:=, =\= |
| Conjunction | Supported | , (comma) for AND |
| Disjunction and if-then-else | Supported | ; and -> |
| Cut and negation | Supported | ! and \+ Goal |
| Type checks | Supported | var, nonvar, atom, number, integer, float, compound, is_list, ground |
| Variables | Full support | Uppercase or _ for anonymous |
Outside the Current Subset
| Feature | Status | Workaround |
|---|---|---|
assert/1, retract/1 |
Not built in | Enter facts directly at prompt |
Built-in append, member, length |
Not built in | Define them yourself (examples below) |
I/O (write, nl, read) |
Not built in | Results shown via query responses |
findall, bagof, setof |
Not built in | Backtracking shows all solutions |
Integer division (//) |
Not built in | Use / for floating-point division or mod for remainders |
Term ordering (@<, @>, @=<, @>=) |
Not built in | Use arithmetic comparisons only on numeric expressions |
Defining Common Predicates
Since member and append are not built-in, define them yourself:
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
append([], L, L).
append([H|T], L, [H|R]) :- append(T, L, R).
Once defined, they work as expected for queries.
Quick Start
This section will have you writing your first Prolog program within minutes of connecting.
Your First Session
- Dial
555-0330to connect to SLP-PROLOG - At the
?-prompt, enter facts directly (one per line):
likes(mary, pizza).
likes(john, pizza).
- Now ask a question -- who likes pizza?
?- likes(Who, pizza).
Who = mary.
Who = john.
Congratulations! You have just created a small database and queried it. Prolog found all the answers that matched your question.
Try These Examples
Family relationships:
parent(tom, mary).
parent(tom, james).
parent(mary, ann).
?- parent(tom, X).
X = mary.
X = james.
Simple arithmetic:
?- X is 3 + 4.
X = 7.
?- X is 10 * 5.
X = 50.
List operations (define predicates first):
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
append([], L, L).
append([H|T], L, [H|R]) :- append(T, L, R).
?- member(X, [red, green, blue]).
X = red.
X = green.
X = blue.
?- append([a,b], [c,d], Result).
Result = [a, b, c, d].
Every statement in Prolog must end with a period (.). Forgetting the period is the most common beginner mistake.
Getting Connected
Dial into the Prolog backend using your modem:
ATDT555-0330
After connection, the Prolog prompt appears:
ATDT555-0330
CONNECT 1200
ISO Prolog Core (subset)
?-
Use a monospaced terminal font and enable local echo if your modem or terminal software does not provide it.
Facts & Rules
Facts declare true statements about the world. Rules define relationships using :- (if) with a body of goals.
parent(alex, jamie).
parent(jamie, robin).
parent(jamie, taylor).
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).
Predicates and atoms begin with lowercase letters. Variables begin with uppercase letters or underscore.
| Form | Meaning |
|---|---|
atom |
Lowercase identifier, e.g., parent |
Variable |
Uppercase identifier, e.g., X, Person |
Functor(Args) |
Predicate with arguments, e.g., parent(alex, jamie) |
Queries
Queries ask Prolog to satisfy goals. Multiple answers are found through backtracking and displayed in sequence.
?- parent(jamie, X).
X = robin.
X = taylor.
?- grandparent(alex, X).
X = robin.
X = taylor.
Queries must end with a period (.). All solutions are computed and displayed in sequence. If no solutions exist, false. is returned.
Lists
Lists are written using brackets. The bar | separates the head from the tail. This is the preferred ISO core subset representation.
[a, b, c]
[Head|Tail]
[H|[T1|T2]]
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
?- member(X, [sun, moon, stars]).
X = sun.
X = moon.
X = stars.
Arithmetic with is
Arithmetic is performed with is, which evaluates the right-hand side and unifies the result with the left-hand side.
double(N, D) :- D is N * 2.
?- double(21, X).
X = 42.
is requires the right-hand side to be fully instantiated. Use it after variables are bound by earlier goals.
Backtracking
Prolog searches for solutions depth-first. When a goal fails, it backtracks to the last choice-point and tries the next alternative.
color(red).
color(green).
color(blue).
pair(X, Y) :- color(X), color(Y).
?- pair(X, Y).
X = red, Y = red.
X = red, Y = green.
X = red, Y = blue.
X = green, Y = red.
X = green, Y = green.
X = green, Y = blue.
X = blue, Y = red.
X = blue, Y = green.
X = blue, Y = blue.
The cut operator (!) is available for committing to the current choice and pruning later alternatives. It is useful for some control patterns, but beginners should still prefer declarative rules when possible.
Implementation Summary
| Category | Support |
|---|---|
| Facts & Rules | Full support - Define facts and rules with :- |
| Queries | Full support - Interactive with all solutions displayed |
| Lists | Full support - Bracket notation and `[H |
| Unification | Full support - = and pattern matching |
| Backtracking | Full support - Depth-first search with choice-points |
| Arithmetic | Supported subset - is with +, -, *, /, mod |
| Comparison | Supported subset - \=, ==, <, >, =<, >=, =:=, =\= |
| Control | Supported subset - conjunction, disjunction, cut, negation as failure, and if-then-else |
| Built-in predicates | Limited - type checks are built in; define member, append, and length yourself |
Tips for Beginners
Learning Prolog requires thinking differently about programming. These tips will help you develop good habits from the start.
Think Declaratively
Instead of asking "What steps do I need to perform?", ask "What relationships exist?" and "What would a correct answer look like?"
% Procedural thinking (wrong approach):
% "Loop through the list, check each element..."
% Declarative thinking (Prolog way):
member(X, [X|_]). % X is a member if it's the head
member(X, [_|T]) :- member(X, T). % or if it's in the tail
Start with Facts
Before writing complex rules, build a solid foundation of facts. Test your facts with simple queries before adding rules that use them.
% Start here:
employee(alice, accounting, 50000).
employee(bob, engineering, 65000).
employee(carol, engineering, 70000).
% Test with simple queries:
?- employee(alice, Dept, _).
Dept = accounting.
% Then add rules:
department_employee(Dept, Name) :- employee(Name, Dept, _).
Use the Anonymous Variable
The underscore _ means "I don't care about this value." Use it to ignore parts of structures you don't need.
% Good: clearly shows we only care about the name
parent_name(Name) :- parent(Name, _).
% Wasteful: Child is never used
parent_name(Name) :- parent(Name, Child).
Name Variables Meaningfully
Variable names should describe what they represent. This makes your code readable and helps catch errors.
% Clear:
grandparent(Grandparent, Grandchild) :-
parent(Grandparent, Parent),
parent(Parent, Grandchild).
% Confusing:
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).
Watch Your Recursion
Recursive rules must have a base case that stops the recursion. Without it, Prolog will search forever.
% CORRECT: Base case comes first
ancestor(X, Y) :- parent(X, Y). % Base case
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y). % Recursive case
% WRONG: No base case - infinite loop
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
Test Incrementally
Build your program piece by piece, testing each part before adding more. When something goes wrong, you will know exactly where to look.
If a query returns false unexpectedly, try simpler queries to isolate the problem. Often a typo in a fact or a missing base case is the culprit.
Solving Problems with Prolog
Once you understand the basics, Prolog becomes a powerful tool for solving real problems. Here are some patterns that demonstrate Prolog's strengths.
Family Tree Example
Build a complete family knowledge base:
% Facts - the basic family data
parent(alice, bob).
parent(alice, carol).
parent(bob, dave).
parent(bob, eve).
parent(carol, frank).
female(alice).
female(carol).
female(eve).
male(bob).
male(dave).
male(frank).
% Rules - derived relationships
mother(X, Y) :- parent(X, Y), female(X).
father(X, Y) :- parent(X, Y), male(X).
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).
grandmother(X, Y) :- grandparent(X, Y), female(X).
Now ask questions:
?- grandmother(X, dave).
X = alice.
?- grandparent(alice, X).
X = dave.
X = eve.
X = frank.
A full sibling rule can use not-unifiable (X \= Y) to prevent someone from being their own sibling. Keep in mind that \= tests whether two terms cannot unify; it is not the same as ISO term non-identity (\==).
List Processing
Prolog excels at recursive list manipulation. First, define the basic predicates:
% Sum all elements in a list
sum([], 0).
sum([H|T], S) :- sum(T, Rest), S is H + Rest.
% Find the last element
last([X], X).
last([_|T], X) :- last(T, X).
Example queries:
?- sum([1, 2, 3, 4], Total).
Total = 10.
?- last([a, b, c], X).
X = c.
Numeric comparison operators (>, <, =<, >=) are available for arithmetic expressions whose variables are already bound. They are not general term-ordering predicates.
Classic Puzzle: Who Owns the Fish?
Prolog shines at logic puzzles. Here is a simplified version using only unification:
% Define possible values
color(red). color(blue). color(green).
pet(dog). pet(cat). pet(bird).
% Solve: Red house has dog, blue house has bird
% GreenPet must be the remaining pet (cat)
solve(RedPet, BluePet, GreenPet) :-
RedPet = dog,
BluePet = bird,
GreenPet = cat.
More complex puzzle solutions can use \= for not-unifiable checks, but the current subset does not include CLP(FD), all_different/1, or standard term-ordering predicates. The example above uses direct assignment for simplicity.
For constraint puzzles: define the possible values, then express each constraint as a rule. Prolog finds assignments that satisfy all constraints simultaneously.
Built-in Predicates Reference
This section documents common ISO Prolog core predicates and operators. Note: SLP-PROLOG currently implements a subset of these. See the "Current Implementation" section for the launch boundary.
Legend: Supported = works now | Outside subset = not built in
Control Predicates
| Predicate | Description | Status |
|---|---|---|
true |
Always succeeds | Outside subset |
fail |
Always fails | Supported |
false |
Always fails | Outside subset |
! |
Cut - commits to current choice, prevents backtracking | Supported |
, |
Conjunction - both goals must succeed | Supported |
; |
Disjunction - either goal may succeed | Supported |
-> |
If-then (used with ; for if-then-else) |
Supported |
\+ Goal |
Negation as failure | Supported |
call(Goal) |
Calls Goal as a goal | Outside subset |
Comparison Predicates
| Predicate | Description | Status |
|---|---|---|
X = Y |
Unification - X and Y can be made identical | Supported |
X \= Y |
Not unifiable - X and Y cannot unify | Supported |
X == Y |
Identical after current bindings | Supported |
X \== Y |
Not identical | Outside subset |
X @< Y |
Term X precedes Y in standard order | Outside subset |
X @> Y |
Term X follows Y in standard order | Outside subset |
X @=< Y |
X precedes or equals Y | Outside subset |
X @>= Y |
X follows or equals Y | Outside subset |
Arithmetic Predicates
| Predicate | Description | Status |
|---|---|---|
X is Expr |
Evaluate Expr and unify with X | Supported |
X < Y |
Arithmetic less than | Supported |
X > Y |
Arithmetic greater than | Supported |
X =< Y |
Arithmetic less than or equal | Supported |
X >= Y |
Arithmetic greater than or equal | Supported |
X =:= Y |
Arithmetic equality | Supported |
X =\= Y |
Arithmetic inequality | Supported |
Arithmetic Operators
| Operator | Description | Status |
|---|---|---|
+ |
Addition | Supported |
- |
Subtraction | Supported |
* |
Multiplication | Supported |
/ |
Division (floating point) | Supported |
// |
Integer division | Outside subset |
mod |
Modulo (remainder) | Supported |
abs(X) |
Absolute value | Outside subset |
min(X,Y) |
Minimum of X and Y | Outside subset |
max(X,Y) |
Maximum of X and Y | Outside subset |
List Predicates
These predicates are not built-in. You must define member and append yourself (see Quick Start section). List syntax [H|T] is fully supported for writing your own list predicates.
| Predicate | Description | Status |
|---|---|---|
append(L1, L2, L3) |
L3 is L1 followed by L2 | User-defined |
length(List, N) |
List has N elements | Outside subset |
member(X, List) |
X is an element of List | User-defined |
reverse(L1, L2) |
L2 is L1 reversed | User-defined |
sort(L1, L2) |
L2 is L1 sorted, duplicates removed | Outside subset |
msort(L1, L2) |
L2 is L1 sorted, duplicates kept | Outside subset |
Type Checking Predicates
| Predicate | Description | Status |
|---|---|---|
atom(X) |
X is an atom | Supported |
number(X) |
X is a number | Supported |
integer(X) |
X is an integer | Supported |
float(X) |
X is a floating-point number | Supported |
compound(X) |
X is a compound term | Supported |
var(X) |
X is an unbound variable | Supported |
nonvar(X) |
X is not an unbound variable | Supported |
is_list(X) |
X is a proper list | Supported |
ground(X) |
X contains no unbound variables | Supported |
Term Manipulation
| Predicate | Description | Status |
|---|---|---|
functor(T, F, A) |
Term T has functor F and arity A | Outside subset |
arg(N, T, A) |
A is the Nth argument of term T | Outside subset |
=..(T, L) |
Univ - T =.. [Functor | Args] |
copy_term(T1, T2) |
T2 is a copy of T1 with fresh variables | Outside subset |
Database Predicates
Facts and rules are added by entering them directly at the prompt, not via assert/1. Dynamic database modification during queries is outside the current subset.
| Predicate | Description | Status |
|---|---|---|
assert(Clause) |
Add clause to database | Outside subset |
asserta(Clause) |
Add clause at beginning | Outside subset |
assertz(Clause) |
Add clause at end | Outside subset |
retract(Clause) |
Remove first matching clause | Outside subset |
abolish(Pred/Arity) |
Remove all clauses for predicate | Outside subset |
Input/Output Predicates
| Predicate | Description | Status |
|---|---|---|
write(X) |
Write term X to output | Outside subset |
writeln(X) |
Write X followed by newline | Outside subset |
nl |
Write a newline | Outside subset |
read(X) |
Read a term from input | Outside subset |
Finding All Solutions
Since SLP-PROLOG automatically displays all solutions via backtracking, findall and related predicates are less critical. The system shows each binding as it finds them.
| Predicate | Description | Status |
|---|---|---|
findall(T, G, L) |
L is list of all T satisfying goal G | Outside subset |
bagof(T, G, L) |
Like findall but fails if no solutions | Outside subset |
setof(T, G, L) |
Like bagof but sorted, no duplicates | Outside subset |
Troubleshooting
Common Error Messages
"Syntax error"
- Check that your statement ends with a period (
.) - Ensure atoms start with lowercase, variables with uppercase
- Verify matching parentheses and brackets
"Undefined procedure"
- The predicate you called does not exist
- Check spelling and arity (number of arguments)
- Remember to define facts/rules before querying them
"Arguments are not sufficiently instantiated"
- Arithmetic with
isrequires the right side to be fully known - Bind variables before using them in arithmetic
% WRONG:
?- X is Y + 1.
ERROR: Arguments are not sufficiently instantiated
% CORRECT:
?- Y = 5, X is Y + 1.
X = 6, Y = 5.
"Out of local stack"
- Your program has infinite recursion
- Check that recursive rules have proper base cases
- Ensure base cases are listed before recursive cases
Query Returns false Unexpectedly
- Check spelling of atoms and predicates
- Verify all required facts exist
- Test simpler queries to isolate the problem
- Check that rule variables are used consistently
Query Never Finishes
- Your program may have infinite recursion
- Press
Ctrl+Cto interrupt (implementation dependent) - Review recursive rules for missing base cases
- Check for circular dependencies in rules
Connection Issues
| Problem | Solution |
|---|---|
| No carrier | Verify phone number: 555-0330 |
| Garbled text | Set terminal to 8N1, match baud rate |
| No echo | Enable local echo in terminal settings |
| Dropped connection | Dial again; sessions are not persistent |
Glossary
Arity
: The number of arguments a predicate takes. parent(tom, mary) has arity 2.
Atom
: A constant value written in lowercase, like red, tom, or hello_world.
Backtracking : Prolog's method of finding alternative solutions by undoing choices and trying different possibilities.
Binding : The association of a variable with a value. When X is bound to 5, X equals 5.
Choice Point : A place in the computation where alternative solutions may exist. Prolog returns here when backtracking.
Clause : A fact or a rule. Facts are clauses with no body; rules have a head and body.
Compound Term
: A term with a functor and arguments, like parent(tom, mary) or point(3, 4).
Conjunction
: Combining goals with comma (,) -- all must succeed.
Cut
: The ! operator, which commits to the current choice and prevents backtracking past it.
Declarative : Describing what is true, rather than how to compute it. Prolog is a declarative language.
Disjunction
: Combining goals with semicolon (;) -- at least one must succeed.
Fact
: A statement that is unconditionally true, like parent(tom, mary).
Functor
: The name of a compound term. In likes(mary, pizza), the functor is likes.
Goal : A query or subgoal that Prolog attempts to satisfy.
Ground Term : A term with no unbound variables.
Head
: The left side of a rule, before :-. The conclusion that follows if the body is true.
Horn Clause : A logical statement with at most one positive literal. Facts and rules in Prolog are Horn clauses.
Instantiated : A variable that has been bound to a value.
List
: An ordered sequence of elements, written as [a, b, c] or [Head|Tail].
Predicate
: A named relation defined by facts and rules. parent and grandparent are predicates.
Query
: A goal submitted at the ?- prompt to find solutions.
Rule
: A conditional statement of the form head :- body. The head is true if the body can be satisfied.
Unification : The process of making two terms identical by finding appropriate variable bindings.
Variable
: A placeholder for values, written starting with uppercase or underscore. Examples: X, Person, _temp.
Quick Reference Card
+------------------------------------------------------------------+
| SLP-PROLOG QUICK REFERENCE |
| Emulator.ca Systems |
+------------------------------------------------------------------+
| |
| DIAL: 555-0330 PROMPT: ?- |
| |
+------------------------------------------------------------------+
| CURRENTLY SUPPORTED |
| |
| fact. State a truth |
| head :- body. Define a rule |
| ?- goal. Ask a query |
| [a, b, c] List |
| [H|T] Head/Tail pattern |
| _ Anonymous variable |
| X is Expr Arithmetic evaluation |
| , AND (conjunction) |
| ; OR ! Cut |
| \+ Negation as failure |
| = Unify \= Not unifiable |
| == Identical < > Less/greater |
| =< >= Less/greater-equal =:= =\= Arithmetic equality/neq |
| + - Add/subtract * / Multiply/divide |
| mod Modulo |
| |
+------------------------------------------------------------------+
| OUTSIDE CURRENT SUBSET |
| |
| // Integer division |
| assert(Fact) (enter facts directly instead) |
| retract(Fact) write(X) nl read(X) |
| findall bagof setof |
| |
+------------------------------------------------------------------+
| DEFINE THESE YOURSELF |
| |
| member(X, [X|_]). |
| member(X, [_|T]) :- member(X, T). |
| |
| append([], L, L). |
| append([H|T], L, [H|R]) :- append(T, L, R). |
| |
+------------------------------------------------------------------+
| EXAMPLES |
| |
| ?- X is 3 + 4. X = 7. |
| ?- member(X, [a,b,c]). X = a ; X = b ; X = c |
| ?- append([1,2], [3,4], X). X = [1,2,3,4]. |
| |
+------------------------------------------------------------------+
Further Exploration
You have learned the fundamentals of logic programming, but this is just the beginning. Prolog has been used to build expert systems that diagnose diseases, parse natural language, prove mathematical theorems, and solve scheduling problems that would take humans weeks to work through.
Some directions to explore:
- Definite Clause Grammars (DCGs) - Prolog's elegant notation for parsing languages
- Meta-programming - Programs that manipulate other programs
- Constraint Logic Programming - Solving optimization problems declaratively
- Natural Language Processing - Parsing and understanding human sentences
The Prolog community has a long tradition of sharing knowledge. Seek out "The Art of Prolog" by Sterling and Shapiro, or "Clause and Effect" by Clocksin, for deeper exploration.
Happy querying!
SLP-PROLOG Language Reference Emulator.ca Systems - DIAL: 555-0330