On this page:
theory/  c
make-theory
write-theory
read-theory
datalog
datalog!
!
~
:  -
?

4 Racket Interoperability

 (require datalog) package: datalog

The Datalog database can be directly used by Racket programs through this API.

Examples:
> (define family (make-theory))
> (datalog family
           (! (parent joseph2 joseph1))
           (! (parent joseph2 lucy))
           (! (parent joseph3 joseph2)))

'()

> (datalog family
           (? (parent X joseph2)))

'(#hasheq((X . joseph3)))

> (datalog family
           (? (parent X (string->symbol "joseph2"))))

'(#hasheq((X . joseph3)))

> (let ([atom 'joseph2])
    (datalog family
             (? (parent X #,atom))))

'(#hasheq((X . joseph3)))

> (let ([table 'parent])
    (datalog family
             (? (#,table X joseph2))))

'(#hasheq((X . joseph3)))

> (datalog family
           (? (parent joseph2 X)))

'(#hasheq((X . joseph1)) #hasheq((X . lucy)))

> (datalog family
           (? (parent joseph2 X))
           (? (parent X joseph2)))

'(#hasheq((X . joseph3)))

> (datalog family
           (! (:- (ancestor A B)
                  (parent A B)))
           (! (:- (ancestor A B)
                  (parent A C)
                  (= D C)
                  (ancestor D B))))

'()

> (datalog family
           (? (ancestor A B)))

'(#hasheq((A . joseph3) (B . joseph2))

  #hasheq((A . joseph2) (B . lucy))

  #hasheq((A . joseph2) (B . joseph1))

  #hasheq((A . joseph3) (B . lucy))

  #hasheq((A . joseph3) (B . joseph1)))

> (let ([x 'joseph2])
    (datalog family
             (? (parent x X))))

'(#hasheq((X . joseph1)) #hasheq((X . lucy)))

> (datalog family
           (? (add1 1 :- X)))

'(#hasheq((X . 2)))

> (datalog family
           (? (add1 X :- 2)))

'()

> (datalog family
           (? (#,(λ (x) (+ x 1)) 1 :- X)))

'(#hasheq((X . 2)))

A contract for Datalog theories.

procedure

(make-theory)  theory/c

Creates a theory for use with datalog.

procedure

(write-theory t [out])  void?

  t : theory/c
  out : output-port? = (current-output-port)
Writes t to out. Source location information is lost.

procedure

(read-theory [in])  theory/c

  in : input-port? = (current-input-port)
Reads and returns a theory from in.

syntax

(datalog thy-expr
         stmt ...)
 
  thy-expr : theory/c
Executes the statements on the theory given by thy-expr. Returns the answers to the final query as a list of substitution dictionaries or returns empty.

syntax

(datalog! thy-expr
         stmt ...)
 
  thy-expr : theory/c
Executes the statements on the theory given by thy-expr. Prints the answers to every query in the list of statements. Returns (void).

Statements are either assertions, retractions, or queries.

syntax

(! clause)

Asserts the clause.

syntax

(~ clause)

Retracts the literal.

syntax

(:- literal question ...)

A conditional clause.

syntax

(? question)

Queries the literal and prints the result literals.

Questions are either literals or external queries.

Literals are represented as identifier or (table term ...).

A table is either an identifier or #,expr where expr evaluates to a symbol.

External queries are represented as (ext-table term ... :- term ...), where ext-table is an identifier bound to a procedure or #,expr where expr evaluates to a procedure that when given the first set of terms as arguments returns the second set of terms as values.

A term is either a non-capitalized identifiers for a constant symbol, a Racket expression for a constant datum, or a capitalized identifier for a variable symbol, or #,expr where expr evaluates to a constant datum. Bound identifiers in terms are treated as the datum they are bound to.

External queries fail if any logic variable is not fully resolved to a datum on the Datalog side. In other words, unbound logic variables never flow to Racket.

External queries invalidate Datalog’s guaranteed termination. For example, this program does not terminate:

(datalog (make-theory)
         (! (:- (loop X)
                (add1 X :- Z)
                (loop Z)))
         (? (loop 1)))