{"size": 4366, "ext": "scrbl", "max_stars_repo_path": "scribblings/tutorial.scrbl", "max_stars_repo_name": "NoahStoryM/datalog", "max_stars_repo_stars_event_min_datetime": "2015-03-24T15:04:28.000Z", "max_stars_repo_stars_event_max_datetime": "2021-12-24T19:09:18.000Z", "max_issues_repo_path": "scribblings/tutorial.scrbl", "max_issues_repo_name": "NoahStoryM/datalog", "max_issues_repo_issues_event_min_datetime": "2017-08-25T20:26:37.000Z", "max_issues_repo_issues_event_max_datetime": "2022-02-26T17:48:40.000Z", "max_forks_repo_path": "share/pkgs/datalog/scribblings/tutorial.scrbl", "max_forks_repo_name": "takikawa/racket-ppa", "max_forks_repo_forks_event_min_datetime": "2015-04-29T05:03:30.000Z", "max_forks_repo_forks_event_max_datetime": "2021-12-17T20:54:02.000Z"}
{"max_stars_count": 33, "max_issues_count": 15, "max_forks_count": 16, "avg_line_length": 40.0550458716, "max_line_length": 130, "alphanum_fraction": 0.6896472744}
#lang scribble/doc
@(require scribble/manual
          scribble/eval
          scribble/basic
          scribble/bnf
          (for-label racket/base
                     racket/contract
                     "../main.rkt")
          "utils.rkt")

@title{Tutorial}

Start DrRacket and type

@racketmod[datalog]

in the Definitions window. Click @onscreen{Run}, then click in the REPL.

@racketinput[]

@tech{Facts} are stored in tables. If the name of the table is @litchar["parent"], and 
@litchar["john"] is the parent of @litchar["douglas"], store the fact in the database with
this:

@racketinput[#,(tt "parent(john, douglas).")]

Each item in the parenthesized list following the name of the table is called a @deftech{term}.
A term can be either a logical @racket[variable] or a @racket[constant].
Thus far, all the terms shown have been constant terms.

A query can be used to see if a particular row is in a table. Type this to see if @litchar["john"]
is the parent of @litchar["douglas"]:

@racketinput[#,(tt "parent(john, douglas)?")]
@racketblock[#,(racketresultfont (tt "parent(john, douglas)."))]

Type this to see if @litchar["john"] is the parent of @litchar["ebbon"]:

@racketinput[#,(tt "parent(john, ebbon)?")]

The query produced no results because @litchar["john"] is not the parent of @litchar["ebbon"]. Let's add more rows.

@racketinput[#,(tt "parent(bob, john).")]
@racketinput[#,(tt "parent(ebbon, bob).")]

Type the following to list all rows in the @litchar["parent"] table:

@racketinput[#,(tt "parent(A, B)?")]
@racketblock[#,(racketresultfont (tt "parent(john, douglas)."))]
@racketblock[#,(racketresultfont (tt "parent(bob, john)."))]
@racketblock[#,(racketresultfont (tt "parent(ebbon, bob)."))]

Type the following to list all the children of @litchar["john"]:

@racketinput[#,(tt "parent(john, B)?")]
@racketblock[#,(racketresultfont (tt "parent(john, douglas)."))]

A term that begins with a capital letter is a logical variable.When producing a set of answers, the
Datalog interpreter lists all rows that match the query when each variable in the query is substituted
for a constant. The following example produces no answers, as there are no substitutions for the variable
@litchar["A"] that produce a fact in the database. This is because no one is the parent of oneself.

@racketinput[#,(tt "parent(A, A)?")]

A deductive database can use rules of inference to derive new facts. Consider the following rule:

@racketinput[#,(tt "ancestor(A, B) :- parent(A, B).")]

The rule says that if A is the parent of B, then A is an ancestor of B.
The other rule defining an ancestor says that if A is the parent of C,
C is an ancestor of B, then A is an ancestor of B.

@racketinput[#,(tt "ancestor(A, B) :-")
             #,(tt "  parent(A, C),")
             #,(tt "  ancestor(C, B).")]

In the interpreter, DrRacket knows that the clause is not complete, so by pressing Return, it doesn't interpret the line.

Rules are used to answer queries just as is done for facts.

@racketinput[#,(tt "ancestor(A, B)?")]
@racketblock[#,(racketresultfont (tt "ancestor(ebbon, bob)."))]
@racketblock[#,(racketresultfont (tt "ancestor(bob, john)."))]
@racketblock[#,(racketresultfont (tt "ancestor(john, douglas)."))]
@racketblock[#,(racketresultfont (tt "ancestor(bob, douglas)."))]
@racketblock[#,(racketresultfont (tt "ancestor(ebbon, john)."))]
@racketblock[#,(racketresultfont (tt "ancestor(ebbon, douglas)."))]
@racketinput[#,(tt "ancestor(X,john)?")]
@racketblock[#,(racketresultfont (tt "ancestor(bob, john)."))]
@racketblock[#,(racketresultfont (tt "ancestor(ebbon, john)."))]

A fact or a rule can be retracted from the database using tilde syntax:

@racketinput[#,(tt "parent(bob, john)~")]
@racketinput[#,(tt "parent(A, B)?")]
@racketblock[#,(racketresultfont (tt "parent(john, douglas)."))]
@racketblock[#,(racketresultfont (tt "parent(ebbon, bob)."))]
@racketinput[#,(tt "ancestor(A, B)?")]
@racketblock[#,(racketresultfont (tt "ancestor(ebbon, bob)."))]
@racketblock[#,(racketresultfont (tt "ancestor(john, douglas)."))]

Unlike Prolog, the order in which clauses are asserted is irrelevant. All queries terminate, and every possible answer is derived.

@racketinput[#,(tt "q(X) :- p(X).")]
@racketinput[#,(tt "q(a).")]
@racketinput[#,(tt "p(X) :- q(X).")]
@racketinput[#,(tt "q(X)?")]
@racketblock[#,(racketresultfont (tt "q(a)."))]
