Your First Program¶
This tutorial builds a small family-tree knowledge base and queries it from
several angles. It mirrors the shipped examples/family-tree.lisp program (see
Examples) but explains each step. By the end you will know how
to state facts, derive new relations with rules, and choose the right query
entry point.
1. Load and enter the package¶
(require :asdf)
(asdf:load-asd (truename "cl-prolog.asd")) ; run from the repository root
(asdf:load-system :cl-prolog)
(in-package #:cl-prolog)
2. State the facts¶
Facts are one-element clauses. Here parent/2 records who is a parent of whom:
define-rulebase is defparameter plus rulebase construction — it binds the
special variable *family* to a rulebase value. There is no global,
process-wide database; every query takes its rulebase explicitly. See the
Rule DSL for the full family of authoring forms.
3. Derive a new relation with rules¶
ancestor/2 is not a fact — it is derived from parent/2. Read the two
clauses as: "X is an ancestor of Y if X is a parent of Y, or if X is a
parent of some Z who is an ancestor of Y."
(define-rulebase *family*
((parent tom bob))
((parent bob alice))
((parent alice eve))
((ancestor ?x ?y) (parent ?x ?y)) ; base case
((ancestor ?x ?y) (parent ?x ?z) (ancestor ?z ?y))) ; recursive case
?x,?y,?zare logic variables.- The clause head is the relation being defined; the goals after it are its body.
- Clauses are tried in definition order, so the base case is attempted first. See Semantics for the exact search order.
4. Ask for every solution¶
query-prolog collects all solutions into a list. Each solution is an
alist binding the query's variables. Tom is an ancestor of Bob (directly),
and of Alice and Eve (transitively).
5. Ask for just the first solution¶
query-prolog-first stops at the first proof and returns that single solution,
or nil if there is none. It is the right tool when you only need one answer.
6. Ask a yes/no question¶
(prolog-succeeds-p *family* '(parent tom bob))
;; => T
(prolog-succeeds-p *family* '(parent bob tom))
;; => NIL
prolog-succeeds-p returns a boolean and stops at the first proof. Use it for
membership-style checks where you do not need the bindings.
7. Run goals as they are proven¶
For large or streaming searches, map-prolog-solutions calls your function
once per solution as it is found, without collecting a list:
(map-prolog-solutions
(lambda (solution)
(format t "~&tom is an ancestor of ~S~%"
(solution-binding '?who solution)))
*family* '(ancestor tom ?who))
solution-binding looks up one variable in a solution alist.
What you learned¶
- Facts are one-element clauses; rules are a head plus body goals.
- Rules can be recursive and are tried in definition order.
query-prologcollects all solutions,query-prolog-firstreturns one,prolog-succeeds-panswers yes/no, andmap-prolog-solutionsstreams.
Next steps¶
- Querying — every entry point, its keywords, and result shapes.
- Builtin Goals — arithmetic, lists, collection, and more.
- Cookbook — recipes that combine these pieces.