Skip to content

Quick Start

This page gets you from a fresh checkout to a working query in a few minutes. For an installation deep-dive, see Installation; for a guided tutorial, see Your First Program.

Load the library

Run from the repository root:

(require :asdf)
(asdf:load-asd (truename "cl-prolog.asd")) ; run from the repository root
(asdf:load-system :cl-prolog)

(in-package #:cl-prolog)

Define a rulebase and query it

(define-rulebase *family*
  ((parent tom bob))
  ((parent bob alice))
  ((ancestor ?x ?y) (parent ?x ?y))
  ((ancestor ?x ?y) (parent ?x ?z) (ancestor ?z ?y)))

(query-prolog *family* '(ancestor tom ?who))
;; => (((?WHO . BOB)) ((?WHO . ALICE)))

That is the whole loop: build a rulebase, then ask it questions.

Reading the syntax

  • Facts are one-element clauses: ((parent tom bob)).
  • Rules are a head clause followed by body goals: ((ancestor ?x ?y) (parent ?x ?y)).
  • Logic variables are ?-prefixed symbols: ?x, ?who.
  • A solution is an alist of query-variable bindings. Two solutions above mean the query proved twice, binding ?who to bob and then to alice.

Ground success vs. failure

A ground proof that binds no variables returns (nil) — a one-element list whose single solution is the empty alist. Failure returns (). See Troubleshooting if that surprises you.

Four ways to ask

(query-prolog *family* '(ancestor tom ?who))          ; all solutions, as a list
(query-prolog *family* '(ancestor tom ?who) :limit 2) ; bounded search
(query-prolog-first *family* '(ancestor ?x bob))      ; first solution or NIL
(prolog-succeeds-p *family* '(ancestor tom eve))      ; boolean, stops at first proof

Streaming — the function is called as each solution is proven:

(map-prolog-solutions
 (lambda (solution) (format t "~&=> ~S~%" solution))
 *family* '(ancestor tom ?who))

See Querying for the full contract of each entry point.

A taste of the builtins

;; arithmetic
(query-prolog (make-rulebase) '(is ?total (+ 20 (* 2 11))))
;; => (((?TOTAL . 42)))

;; list relations need no rulebase clauses at all
(query-prolog (make-rulebase) '(append ?l ?r (a b c)))

;; collect every solution of a subgoal into a bag
(query-prolog *family* '(findall ?child (parent tom ?child) ?children))
;; => (((?CHILDREN BOB)))

The full catalogue lives in Builtin Goals.

Where to go next