Summary of Datalog language deviations
Getty Ritter
7 years ago
3 | 3 | standard Datalog is the existence of a simple type system for rows as |
4 | 4 | well as a choice of tuple- or record-structured data. |
5 | 5 | |
6 | Typical datalog facts are tuple-structured: | |
6 | # Deviation 1: Record-Structured Data | |
7 | ||
8 | Any place where Datalog uses tuple-structured data (i.e. where you | |
9 | have comma-separated expressions in between parentheses) you can also | |
10 | use record-structured data, which allow fields to appear in any | |
11 | order. So the classic example | |
7 | 12 | |
8 | 13 | ``` |
9 |
|
|
14 | - parent ( terry, austin ). | |
10 | 15 | ``` |
11 | 16 | |
12 | Facts are inserted into the database by stating them. | |
17 | can be expressed nearly equivalently using record-structured data as | |
13 | 18 | |
14 | 19 | ``` |
15 |
|
|
20 | - parent { parent: terry, child: austin }. | |
16 | 21 | ``` |
17 | 22 | |
18 | Queries against this are done in the typical Datalog way: | |
23 | Similarly, a query to find all the children of `terry` could be | |
24 | written as | |
19 | 25 | |
20 | 26 | ``` |
21 | ancestor(X, Y) :- parent(X, Y). | |
22 | ancestor(X, Y) :- ancestor(X, Z), parent(Z, Y). | |
27 | - parent { parent: terry, child: X }? | |
23 | 28 | ``` |
24 | 29 | |
25 | However, for utility, you can also express this in a record-structured | |
26 | way with field names. Predicates/queries can also use record | |
27 | structures, which act as keyword arguments. | |
30 | # Deviation 2: Static Types | |
31 | ||
32 | Datalog facts are usually dynamically typed, but this implementation | |
33 | requires (in part to support the syntax above) that facts and | |
34 | predicates have a consistent statically known type. For facts, this | |
35 | often involves a "table declaration" which dictates the structure of | |
36 | all future facts in that table. Some table declarations might look | |
37 | like | |
28 | 38 | |
29 | 39 | ``` |
30 | table parent { parent : atom, child : atom }. | |
31 | parent { parent: terry, child: austin }. | |
32 | ancestor { parent: X, child: Y } | |
33 | :- parent { parent: X, child: Y }. | |
34 | ancestor { parent: X, child: Y } | |
35 | :- ancestor { parent: X, child: Z }, parent { parent: X, child: Y }. | |
40 | - @table edge ( integer, integer ). | |
41 | - @table parent { parent: atom, child: atom }. | |
36 | 42 | ``` |
43 | ||
44 | Queries also have static types, but these can _generally_ be inferred | |
45 | from context in Datalog, and so do not need to be defined. If | |
46 | necessary, though, a `query` definition can be used. | |
47 | ||
48 | ``` | |
49 | - @query ancestor { parent: atom, child: atom }. | |
50 | - ancestor { parent: X, child: Y} | |
51 | :- parent { parent: X, child: Y }. | |
52 | - ancestor { parent: X, child: Y} | |
53 | :- parent { parent: X, child: Z}, | |
54 | ancestor { parent: X, child: Y }. | |
55 | ``` | |
56 | ||
57 | # Deviation 3: Implicit Variables | |
58 | ||
59 | When defining a table's type signature, we can also include a few | |
60 | extra annotations about the meaning of that variable. For example, we | |
61 | might want a particular field of a table to be an auto-incrementing | |
62 | integer, so that every row would include a fresh value without us | |
63 | having to discover it first. If we define a table with the | |
64 | `@autoincrement` keyword, like so | |
65 | ||
66 | ``` | |
67 | - @table person { id: integer @autoincrement, name: string }. | |
68 | ``` | |
69 | ||
70 | then we can use the placeholder `@auto` value, which mean Datalog will | |
71 | examine the table to find the necessary "next" value. | |
72 | ||
73 | ``` | |
74 | - person { id: @auto, name: "alice" }. | |
75 | - person { id: @auto, name: "bob" }. | |
76 | - person { id: @auto, name: "carol" }. | |
77 | ``` |