Skip to content

Templates

George Kastrinis edited this page Oct 2, 2020 · 7 revisions

Templates are blocks of Datalog code that can be instantiated multiple times and connect with other template instantiations. They provide a way to split a Datalog program into module-like parts. Template code can only see parts of the environment that are passed as parameters to the template during instantiation. On the opposite direction, template code is visible to anyone on the outside.

Declaration

template Simple {
	Z(x) : int
	P(x) : string
	Q(x) <- Z(x), P(x)
}

A template may extend another template. Extending a template has the semantics of simply including its contents in the second template. Currently, templates cannot be nested.

template Base {
	P3(x) <- Q(x)
}

template Core : Base {
	P4(x) <- P3(x)
}

The above snippet is equivalent to the following

template Core {
	P3(x) <- Q(x)
	P4(x) <- P3(x)
}

Instantiation

Instantiations of components happen using the as keyword.

Simple as Step1, Step2

Instantiating a component has the semantics of cloning every Datalog clause it contains, differentiating them by qualifying them with the instantiation id. In the above snippet, instantiating component Simple as Step1 is semantically equivalent to the following

Step1.Z(x) : int
Step1.P(x) : string
Step1.Q(x) <- Step1.Z(x), Step1.P(x)

Step2.Z(x) : int
Step2.P(x) : string
Step2.Q(x) <- Step2.Z(x), Step2.P(x)

Parameters

Templates may access code from other instantiations through their parameters.

template Base <X> {
	P1(x) <- X.P(x)
	P1(x) : string
}

template Core <T, G> : Base <G>  {
	P2(x) <- G.Q(x, _)
	P3(x) <- G.Q(_, x)
	W(x) <- T.Z(x)
	M(x) <- P3(x), !W(x)
	M(x) <- W(x), x>1000
}

In the snippet above, T and G are parameters of template Core that abstractly refer to other instantiated templates. Relations and types from those parameters are accessed via qualifying them with the parameter name (e.g. G.Q).

Parameter passing happens during template instantiation. As a convention, the global scope can also be passed as a template parameter with the name _.

Base<_> as S1
Simple as S2
Core<S2, _> as S3

Misc

Types have similar behavior to relations. They can be referred via template parameters, and types declared in a template are visible to the outside world.

@type Shape

template Test<B> {
	Z(x) <- B.Q(x)
	@Type Animal
	@type Circle : A.Shape
	ZZ(x, y) : int, A.Shape
}
Test<_> as T1

Bar(x, y) : int, T1.Animal
@type Cat : T1.Animal

In general, template code is read-only for the outside world. Relations and types can be used in other places, but no outside declarations or rules are allowed to inject anything to a template. The following rule for relation W is valid.

template Simple {
	Z(x) : int
	P(x) : string
	Q(x) <- Z(x), P(x)
}
Simple as S1
W(x) <- S1.Q(x)

But the following are invalid usages.

@type S1.Animal // ERROR
S1.P(x) <- Z(x) // ERROR

An exception is the @output annotation that is allowed to appear in global scope while referring to a relation declared in a template.

Simple as S1, S2, S3, S4
@output S3.Q
Clone this wiki locally