Introduction
Every logic program consists of three fundamental components: facts, rules, and queries. Understanding how to effectively use these components is essential for writing correct and efficient logic programs.
- Facts represent base knowledge that is unconditionally true
- Rules define relationships and conditional truths
- Queries ask questions about the facts and rules
In this article, we’ll explore each component in depth and learn how to construct effective logic programs.
Facts: Base Knowledge
Facts are the foundation of a logic program. They represent unconditional truths about the world.
Syntax
A fact is a predicate followed by arguments in parentheses, ending with a period:
predicate(argument1, argument2, ..., argumentN).
Examples
Simple facts:
% Unary predicates (one argument)
human(socrates).
human(plato).
human(aristotle).
% Binary predicates (two arguments)
parent(tom, bob).
parent(bob, ann).
likes(mary, wine).
% Ternary predicates (three arguments)
teaches(professor_smith, math, monday).
teaches(professor_jones, physics, tuesday).
% Higher-arity predicates
location(building_a, room_101, floor_1, campus_main).
Fact Characteristics
Unconditional: Facts are always true; they don’t depend on conditions.
% These are facts - they're always true
parent(tom, bob).
age(tom, 65).
Ground terms: Facts typically contain only constants (atoms and numbers), not variables.
% Valid facts (ground terms)
parent(tom, bob).
age(tom, 65).
color(apple, red).
% Not typically facts (contain variables)
parent(X, Y). % This is a query or rule head, not a fact
Extensional knowledge: Facts represent explicit knowledge about specific instances.
% Extensional knowledge - specific facts
parent(tom, bob).
parent(bob, ann).
parent(bob, pat).
Organizing Facts
By predicate:
% All parent facts together
parent(tom, bob).
parent(bob, ann).
parent(bob, pat).
% All age facts together
age(tom, 65).
age(bob, 40).
age(ann, 15).
By domain:
% Family facts
parent(tom, bob).
parent(bob, ann).
% Work facts
works_at(tom, company_a).
works_at(bob, company_b).
% Hobby facts
likes(tom, golf).
likes(bob, tennis).
Rules: Relationships and Conditions
Rules define relationships between facts and allow us to derive new knowledge from existing facts.
Syntax
A rule has a head (conclusion) and a body (conditions), separated by :-:
head :- body.
The body can contain multiple conditions separated by commas (logical AND):
head :- condition1, condition2, condition3.
Examples
Simple rules:
% Rule: X is a grandparent of Z if X is a parent of Y and Y is a parent of Z
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
% Rule: X is a sibling of Y if they share a parent
sibling(X, Y) :- parent(P, X), parent(P, Y), X \= Y.
% Rule: X is an adult if X is at least 18 years old
adult(X) :- age(X, A), A >= 18.
Recursive rules:
% Rule: X is an ancestor of Y if X is a parent of Y
ancestor(X, Y) :- parent(X, Y).
% Rule: X is an ancestor of Y if X is a parent of Z and Z is an ancestor of Y
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
Rules with multiple conditions:
% Rule: X can adopt Y if X is an adult and X has sufficient income
can_adopt(X, Y) :- adult(X), income(X, I), I >= 50000, not_parent(X, Y).
% Rule: X is a valid employee if X is an adult, has a job, and passes background check
valid_employee(X) :- adult(X), employed(X), background_check(X).
Rule Components
Head: The conclusion we’re trying to prove.
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
% ^^^^^^^ Head
Body: The conditions that must be satisfied.
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Body
Conditions: Individual goals in the body, separated by commas.
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
% ^^^^^^^^^^^^ ^^^^^^^^^^^^
% Condition 1 Condition 2
Intensional vs. Extensional Knowledge
Extensional knowledge (facts): Explicit instances.
% Facts - extensional knowledge
parent(tom, bob).
parent(bob, ann).
parent(bob, pat).
Intensional knowledge (rules): General relationships.
% Rules - intensional knowledge
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
Rule Evaluation
When the system evaluates a rule, it:
- Tries to unify the head with the query
- Attempts to prove all conditions in the body
- If all conditions succeed, the rule succeeds
- If any condition fails, the rule fails and backtracks
Example:
% Facts
parent(tom, bob).
parent(bob, ann).
% Rule
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
% Query: ?- grandparent(tom, ann).
% Evaluation:
% 1. Unify grandparent(tom, ann) with head grandparent(X, Z)
% โ X = tom, Z = ann
% 2. Try to prove parent(tom, Y), parent(Y, ann)
% 3. Find parent(tom, bob) โ Y = bob
% 4. Try to prove parent(bob, ann)
% 5. Find parent(bob, ann) โ Success!
% Answer: yes
Queries: Asking Questions
Queries ask the system to find values that satisfy certain conditions or to verify that certain statements are true.
Syntax
A query starts with ?- and ends with a period:
?- goal.
Multiple goals are separated by commas (logical AND):
?- goal1, goal2, goal3.
Types of Queries
Verification queries: Check if something is true.
% Is tom a parent of bob?
?- parent(tom, bob).
% Answer: yes
% Is tom a parent of ann?
?- parent(tom, ann).
% Answer: no
Retrieval queries: Find values that satisfy conditions.
% Who is a parent of bob?
?- parent(X, bob).
% Answer: X = tom
% Who are the children of bob?
?- parent(bob, X).
% Answer: X = ann ;
% X = pat
Complex queries: Multiple conditions.
% Who is a grandparent of ann?
?- grandparent(X, ann).
% Answer: X = tom
% Who is a parent of bob and a grandparent of ann?
?- parent(tom, X), grandparent(X, ann).
% Answer: X = bob
% Find all grandparent-grandchild pairs
?- grandparent(X, Y).
% Answer: X = tom, Y = ann ;
% X = tom, Y = pat ;
% X = bob, Y = jim
Query Execution
When the system executes a query, it:
- Tries to unify the query with facts
- If no fact matches, tries to unify with rule heads
- For matching rules, attempts to prove the rule body
- Uses backtracking to find alternative solutions
- Returns all solutions or indicates failure
Example:
% Facts
parent(tom, bob).
parent(bob, ann).
parent(bob, pat).
% Query: ?- parent(X, Y).
% Execution:
% 1. Try first fact: parent(tom, bob) โ X = tom, Y = bob
% 2. User asks for more (;)
% 3. Try second fact: parent(bob, ann) โ X = bob, Y = ann
% 4. User asks for more (;)
% 5. Try third fact: parent(bob, pat) โ X = bob, Y = pat
% 6. No more facts โ Done
Putting It Together: Complete Programs
Example 1: Family Relationships
% ===== FACTS =====
parent(tom, bob).
parent(bob, ann).
parent(bob, pat).
parent(pat, jim).
% ===== RULES =====
% X is a grandparent of Z if X is a parent of Y and Y is a parent of Z
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
% X is an ancestor of Y if X is a parent of Y
ancestor(X, Y) :- parent(X, Y).
% X is an ancestor of Y if X is a parent of Z and Z is an ancestor of Y
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
% X and Y are siblings if they share a parent and are different people
sibling(X, Y) :- parent(P, X), parent(P, Y), X \= Y.
% ===== QUERIES =====
?- parent(tom, bob). % Is tom a parent of bob? โ yes
?- parent(X, bob). % Who is a parent of bob? โ X = tom
?- grandparent(tom, ann). % Is tom a grandparent of ann? โ yes
?- ancestor(tom, jim). % Is tom an ancestor of jim? โ yes
?- sibling(ann, pat). % Are ann and pat siblings? โ yes
Example 2: Employee Management
% ===== FACTS =====
employee(alice, engineering, 80000).
employee(bob, sales, 60000).
employee(charlie, engineering, 75000).
employee(diana, management, 90000).
manages(diana, alice).
manages(diana, bob).
manages(diana, charlie).
% ===== RULES =====
% X is a manager if X manages someone
manager(X) :- manages(X, _).
% X earns more than Y if X's salary is greater than Y's
earns_more(X, Y) :-
employee(X, _, SX),
employee(Y, _, SY),
SX > SY.
% X is a high earner if X earns more than 75000
high_earner(X) :- employee(X, _, S), S > 75000.
% X is in the same department as Y if they work in the same department
same_department(X, Y) :-
employee(X, D, _),
employee(Y, D, _),
X \= Y.
% ===== QUERIES =====
?- employee(alice, D, S). % What department and salary for alice?
?- manager(X). % Who is a manager?
?- earns_more(alice, bob). % Does alice earn more than bob?
?- high_earner(X). % Who is a high earner?
?- same_department(alice, X). % Who works with alice?
Example 3: Knowledge Base
% ===== FACTS =====
% Properties
color(apple, red).
color(banana, yellow).
color(grass, green).
fruit(apple).
fruit(banana).
plant(grass).
% Relationships
contains(apple, seeds).
contains(banana, seeds).
contains(grass, seeds).
% ===== RULES =====
% X is edible if X is a fruit
edible(X) :- fruit(X).
% X is a living_thing if X is a plant or a fruit
living_thing(X) :- plant(X).
living_thing(X) :- fruit(X).
% X and Y have the same color if they are both the same color
same_color(X, Y) :- color(X, C), color(Y, C), X \= Y.
% X is a seed_container if X contains seeds
seed_container(X) :- contains(X, seeds).
% ===== QUERIES =====
?- fruit(apple). % Is apple a fruit? โ yes
?- color(X, red). % What is red? โ X = apple
?- edible(X). % What is edible? โ X = apple ; X = banana
?- living_thing(X). % What is a living thing? โ X = grass ; X = apple ; X = banana
?- same_color(apple, X). % What has the same color as apple? โ no
?- seed_container(X). % What contains seeds? โ X = apple ; X = banana ; X = grass
Common Patterns
Pattern 1: Recursive Rules
Recursive rules allow us to express relationships that apply at any depth.
% Base case: X is an ancestor of Y if X is a parent of Y
ancestor(X, Y) :- parent(X, Y).
% Recursive case: X is an ancestor of Y if X is a parent of Z and Z is an ancestor of Y
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
% Query: Find all ancestors of jim
?- ancestor(X, jim).
% Answer: X = pat ;
% X = bob ;
% X = tom
Pattern 2: Negation
Use \+ (negation as failure) to express “not”.
% X is an only child if X is a child and X has no siblings
only_child(X) :- parent(_, X), \+ sibling(X, _).
% X is unemployed if X is not employed
unemployed(X) :- person(X), \+ employed(X).
Pattern 3: Aggregation
Combine multiple facts to derive conclusions.
% X is a team_lead if X manages at least one person
team_lead(X) :- manages(X, _).
% X is a department_head if X manages multiple people
department_head(X) :- manages(X, Y1), manages(X, Y2), Y1 \= Y2.
Pattern 4: Conditional Logic
Express if-then-else using multiple rules.
% X is a senior if X has more than 10 years of experience
% Otherwise, X is a junior
seniority(X, senior) :- experience(X, Y), Y > 10.
seniority(X, junior) :- experience(X, Y), Y =< 10.
% Query
?- seniority(alice, Level).
% Answer: Level = senior (if alice has > 10 years)
% Level = junior (if alice has <= 10 years)
Best Practices
1. Use Descriptive Predicate Names
% Good
parent(tom, bob).
is_adult(alice).
manages(diana, alice).
% Avoid
p(tom, bob).
a(alice).
m(diana, alice).
2. Organize Facts and Rules
% Group related facts
parent(tom, bob).
parent(bob, ann).
parent(bob, pat).
% Group related rules
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
3. Use Comments
% Family relationships
parent(tom, bob).
parent(bob, ann).
% X is a grandparent of Z if X is a parent of Y and Y is a parent of Z
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
4. Avoid Infinite Loops
% Bad: Can cause infinite recursion
ancestor(X, Y) :- ancestor(X, Z), parent(Z, Y).
% Good: Base case first
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
5. Use Constraints Effectively
% Good: Constraints reduce search space
adult(X) :- age(X, A), A >= 18.
% Less efficient: No constraints
adult(X) :- age(X, A), A >= 18.
adult(X) :- age(X, A), A >= 21.
Glossary
- Fact: An unconditional statement that is true
- Rule: A conditional statement defining relationships
- Query: A question asked to the system
- Head: The conclusion part of a rule
- Body: The conditions part of a rule
- Clause: A fact or rule
- Predicate: A relation or property (e.g., parent/2)
- Argument: A parameter to a predicate
- Arity: The number of arguments a predicate takes
- Ground term: A term containing no variables
- Unification: Pattern matching that binds variables
- Backtracking: Exploring alternative solutions
- Extensional knowledge: Explicit facts about instances
- Intensional knowledge: General rules and relationships
Practice Problems
Problem 1: Writing Facts
Write facts for the following:
- Alice is a student
- Bob is a teacher
- Alice studies mathematics
- Bob teaches mathematics
Solution:
student(alice).
teacher(bob).
studies(alice, mathematics).
teaches(bob, mathematics).
Problem 2: Writing Rules
Write rules for:
- X is a scholar if X is a student or a teacher
- X and Y study together if they study the same subject
- X is a math expert if X teaches mathematics
Solution:
scholar(X) :- student(X).
scholar(X) :- teacher(X).
study_together(X, Y) :- studies(X, S), studies(Y, S), X \= Y.
math_expert(X) :- teaches(X, mathematics).
Problem 3: Writing Queries
Using the facts and rules from Problems 1 and 2, write queries for:
- Is alice a student?
- Who is a teacher?
- What does alice study?
- Who is a scholar?
Solution:
?- student(alice).
?- teacher(X).
?- studies(alice, X).
?- scholar(X).
Problem 4: Complete Program
Write a complete program (facts, rules, queries) for a simple library system with:
- Books with titles and authors
- Members who borrow books
- Rules to find books by author, members who borrowed a book, etc.
Solution:
% Facts
book(the_hobbit, tolkien).
book(1984, orwell).
book(dune, herbert).
member(alice).
member(bob).
borrows(alice, the_hobbit).
borrows(bob, 1984).
borrows(alice, dune).
% Rules
books_by_author(Author, Book) :- book(Book, Author).
borrowed_by(Book, Member) :- borrows(Member, Book).
member_books(Member, Book) :- borrows(Member, Book).
% Queries
?- book(X, tolkien). % What books by tolkien?
?- borrows(alice, X). % What books does alice borrow?
?- member_books(bob, X). % What books does bob borrow?
Related Resources
Online Platforms
- SWI-Prolog Official - Leading Prolog implementation
- Learn Prolog Now! - Interactive tutorial
- Prolog Tutorial - Comprehensive guide
- Prolog Basics Course - Coursera course
- Prolog Examples - Online examples
Interactive Tools
- SWISH - Web-based IDE
- Prolog Online Compiler - Quick testing
- Prolog Visualizer - Trace execution
- SWI-Prolog IDE - Full environment
- Datalog Playground - Datalog environment
Recommended Books
- “Programming in Prolog” by Clocksin & Mellish - Classic introduction
- “The Art of Prolog” by Sterling & Shapiro - Advanced techniques
- “Prolog and Natural Language Analysis” by Pereira & Shieber - NLP applications
- “Logic Programming: The 1st and 2nd Conferences” - Historical perspective
- “Constraint Logic Programming” by Jaffar & Maher - CLP overview
Academic Journals
- Journal of Logic Programming - Primary research
- Theory and Practice of Logic Programming - Current research
- ACM Transactions on Programming Languages - Language design
- Artificial Intelligence - AI applications
- Computational Linguistics - NLP applications
Software Tools
- SWI-Prolog - Most popular Prolog
- GNU Prolog - Free implementation
- XSB Prolog - Tabling support
- Ciao Prolog - Modern Prolog
- Datalog Educational System - Datalog learning
Conclusion
Facts, rules, and queries are the three fundamental components of logic programming:
- Facts provide the base knowledge
- Rules define relationships and derive new knowledge
- Queries ask questions and retrieve answers
By mastering these components, you can construct effective logic programs that express complex relationships and solve problems through logical inference.
In the next article, we’ll explore unification and pattern matching, the mechanisms that enable logic programming to work.
Next Article: Unification and Pattern Matching
Previous Article: Introduction to Logic Programming
Comments