The classic example to showcase Logic Programming, running on Takmela/Datalog! This example has a relatively straighforward query with a medium-length trace.
All ancestors examples: Short / Medium / Longer trace. (Note that the fact set is slightly different in each example)
Program
parent("a", "b").
parent("b", "c").
parent("c", "d").
parent("d", "e").
// All parents are ancestors
ancestor(X, Y):- parent(X, Y).
// An ancestor of an ancestor is also an ancestor
ancestor(X, Y):- ancestor(X, Z), ancestor(Z, Y).
Query
ancestor(b, X)
In the actual trace we use 'a' to mean ancestor and 'p' to mean parent.
Hint: Hovering over a graph expands it
Trace appears confusing? This might help
| Call start rule | |||
![]() |
#0: Called a(b, ?) at the top level (will process)
Processing a(b, ?) codePos a(X, Y)→•p(X|b,Y)
Calling fact: p(b, ?)
Found fact: p(b, ?) → [b, c]
Processing a(b, ?) codePos a(X, Y)→•a(X|b,Z), a(Z,Y)
Calling: a(b, ?) [already processed]
|
||
p(b, ?) → [b, c]
| |||
| Iteration 0 | |||
| |||
![]() |
#1: JoinS: p(b, ?) → [b, c] will resume cont: a(X, Y)→p(X|b,Y)•
newVars: {Y=c} Processing a(b, ?) codePos a(X, Y)→p(X|b,Y|c)•
Reached end of rule, success! a(b, ?) → [b, c]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
| |||
| Iteration 1 | |||
| |||
![]() |
#2: JoinS: a(b, ?) → [b, c] will resume cont: a(X, Y)→a(X|b,Z)•a(Z,Y)
newVars: {Z=c} Processing a(b, ?) codePos a(X, Y)→a(X|b,Z|c)•a(Z|c,Y)
Calling: a(c, ?) [will process]
Processing a(c, ?) codePos a(X, Y)→•p(X|c,Y)
Calling fact: p(c, ?)
Found fact: p(c, ?) → [c, d]
Processing a(c, ?) codePos a(X, Y)→•a(X|c,Z), a(Z,Y)
Calling: a(c, ?) [already processed]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
| |||
![]() |
#3: JoinS: a(b, ?) → [b, c] will resume cont: Root("b", V0)→a("b",V0)•
newVars: {V0=c} Processing Root() codePos Root("b", V0)→a("b",V0|c)•
Reached end of rule, success! Root() → [b, c]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
| |||
| Iteration 2 | |||
| |||
![]() |
#4: JoinS: p(c, ?) → [c, d] will resume cont: a(X, Y)→p(X|c,Y)•
newVars: {Y=d} Processing a(c, ?) codePos a(X, Y)→p(X|c,Y|d)•
Reached end of rule, success! a(c, ?) → [c, d]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
| |||
| Iteration 3 | |||
| |||
![]() |
#5: JoinS: a(c, ?) → [c, d] will resume cont: a(X, Y)→a(X|b,Z|c), a(Z|c,Y)•
newVars: {Y=d} Processing a(b, ?) codePos a(X, Y)→a(X|b,Z|c), a(Z|c,Y|d)•
Reached end of rule, success! a(b, ?) → [b, d]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
| |||
![]() |
#6: JoinS: a(c, ?) → [c, d] will resume cont: a(X, Y)→a(X|c,Z)•a(Z,Y)
newVars: {Z=d} Processing a(c, ?) codePos a(X, Y)→a(X|c,Z|d)•a(Z|d,Y)
Calling: a(d, ?) [will process]
Processing a(d, ?) codePos a(X, Y)→•p(X|d,Y)
Calling fact: p(d, ?)
Found fact: p(d, ?) → [d, e]
Processing a(d, ?) codePos a(X, Y)→•a(X|d,Z), a(Z,Y)
Calling: a(d, ?) [already processed]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
| |||
| Iteration 4 | |||
| |||
![]() |
#7: JoinS: a(b, ?) → [b, d] will resume cont: a(X, Y)→a(X|b,Z)•a(Z,Y)
newVars: {Z=d} Processing a(b, ?) codePos a(X, Y)→a(X|b,Z|d)•a(Z|d,Y)
Calling: a(d, ?) [already processed]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
| |||
![]() |
#8: JoinS: a(b, ?) → [b, d] will resume cont: Root("b", V0)→a("b",V0)•
newVars: {V0=d} Processing Root() codePos Root("b", V0)→a("b",V0|d)•
Reached end of rule, success! Root() → [b, d]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
| |||
![]() |
#9: JoinS: p(d, ?) → [d, e] will resume cont: a(X, Y)→p(X|d,Y)•
newVars: {Y=e} Processing a(d, ?) codePos a(X, Y)→p(X|d,Y|e)•
Reached end of rule, success! a(d, ?) → [d, e]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
a(d, ?) → [d, e]
| |||
| Iteration 5 | |||
| |||
![]() |
#10: JoinS: a(d, ?) → [d, e] will resume cont: a(X, Y)→a(X|b,Z|d), a(Z|d,Y)•
newVars: {Y=e} Processing a(b, ?) codePos a(X, Y)→a(X|b,Z|d), a(Z|d,Y|e)•
Reached end of rule, success! a(b, ?) → [b, e]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
a(d, ?) → [d, e]
a(b, ?) → [b, e]
| |||
![]() |
#11: JoinS: a(d, ?) → [d, e] will resume cont: a(X, Y)→a(X|c,Z|d), a(Z|d,Y)•
newVars: {Y=e} Processing a(c, ?) codePos a(X, Y)→a(X|c,Z|d), a(Z|d,Y|e)•
Reached end of rule, success! a(c, ?) → [c, e]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
a(d, ?) → [d, e]
a(b, ?) → [b, e]
a(c, ?) → [c, e]
| |||
![]() |
#12: JoinS: a(d, ?) → [d, e] will resume cont: a(X, Y)→a(X|d,Z)•a(Z,Y)
newVars: {Z=e} Processing a(d, ?) codePos a(X, Y)→a(X|d,Z|e)•a(Z|e,Y)
Calling: a(e, ?) [will process]
Processing a(e, ?) codePos a(X, Y)→•p(X|e,Y)
Calling fact: p(e, ?)
Processing a(e, ?) codePos a(X, Y)→•a(X|e,Z), a(Z,Y)
Calling: a(e, ?) [already processed]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
a(d, ?) → [d, e]
a(b, ?) → [b, e]
a(c, ?) → [c, e]
| |||
| Iteration 6 | |||
| |||
![]() |
#13: JoinS: a(b, ?) → [b, e] will resume cont: a(X, Y)→a(X|b,Z)•a(Z,Y)
newVars: {Z=e} Processing a(b, ?) codePos a(X, Y)→a(X|b,Z|e)•a(Z|e,Y)
Calling: a(e, ?) [already processed]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
a(d, ?) → [d, e]
a(b, ?) → [b, e]
a(c, ?) → [c, e]
| |||
![]() |
#14: JoinS: a(b, ?) → [b, e] will resume cont: Root("b", V0)→a("b",V0)•
newVars: {V0=e} Processing Root() codePos Root("b", V0)→a("b",V0|e)•
Reached end of rule, success! Root() → [b, e]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
a(d, ?) → [d, e]
a(b, ?) → [b, e]
a(c, ?) → [c, e]
Root() → [b, e]✓
| |||
![]() |
#15: JoinS: a(c, ?) → [c, e] will resume cont: a(X, Y)→a(X|b,Z|c), a(Z|c,Y)•
newVars: {Y=e} Processing a(b, ?) codePos a(X, Y)→a(X|b,Z|c), a(Z|c,Y|e)•
Reached end of rule, success! a(b, ?) → [b, e]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
a(d, ?) → [d, e]
a(b, ?) → [b, e]
a(c, ?) → [c, e]
Root() → [b, e]✓
a(b, ?) → [b, e]
| |||
![]() |
#16: JoinS: a(c, ?) → [c, e] will resume cont: a(X, Y)→a(X|c,Z)•a(Z,Y)
newVars: {Z=e} Processing a(c, ?) codePos a(X, Y)→a(X|c,Z|e)•a(Z|e,Y)
Calling: a(e, ?) [already processed]
|
||
p(b, ?) → [b, c]
a(b, ?) → [b, c]
p(c, ?) → [c, d]
Root() → [b, c]✓
a(c, ?) → [c, d]
a(b, ?) → [b, d]
p(d, ?) → [d, e]
Root() → [b, d]✓
a(d, ?) → [d, e]
a(b, ?) → [b, e]
a(c, ?) → [c, e]
Root() → [b, e]✓
a(b, ?) → [b, e]
| |||
| Iteration 7 | |||
| |||
| (No new calls or successes that can be further processed) | |||
| Iteration 8 [Fixed point reached] | |||