## Local Predicates

Flix supports an abstract mechanism called local predicates. A local predicate, like a local variable, is not visible to the outside.

To understand local predicates, consider the following example: We can a write a function that returns a Datalog program value which computes whether a graph has a cycle:

``````def cyclic(): #{Edge(Int32, Int32), Path(Int32, Int32), Cyclic()} = #{
Path(x, y) :- Edge(x, y).
Path(x, z) :- Path(x, y), Edge(y, z).
Cyclic() :- Path(x, x).
}

def main(): Unit \ IO =
let db = #{
Edge(1, 2).
Edge(2, 3).
Edge(3, 1).
};
query db, cyclic() select true from Cyclic() |> println
``````

Here the `cyclic` function returns a Datalog program value which consists of three rules that compute the transitive closure of a graph of edges and whether there is path from a vertex to itself. We use the `cyclic` function inside `main` to determine if a small graph, given by `db`, has a cyclic. The program prints `Vector#{true}` when compiled and run.

Returning to `cyclic`, we see that its type is:

``````def cyclic(): #{Edge(Int32, Int32), Path(Int32, Int32), Cyclic()} = ...
``````

This is sensible because the Datalog program value uses the predicate symbols `Edge`, `Path` and `Cyclic` with their given types. However, if we think more about it, we can realize that the `Path` predicate is really local to the computation: We are not meant to see it from the outside; it is an implementation detail! What we really want is that `Edge(Int32, Int32)` should be an input and `Cyclic()` should be an output. More importantly, `Path(Int32, Int32)` should not be visible from the outside nor part of the type. We can achieve this with predicate abstraction:

``````def cyclic(): #{Edge(Int32, Int32), Cyclic()} =
#(Edge, Cyclic) -> #{
Path(x, y) :- Edge(x, y).
Path(x, z) :- Path(x, y), Edge(y, z).
Cyclic() :- Path(x, x).
}
``````

Here we use the syntax `#(Edge, Cyclic) -> v` to specific that only the predicates `Edge` and `Cyclic` from within `v` should be visible to the outside. Thus we can omit `Path(Int32, Int32)` from the return type of `cyclic`. Moreover, the Datalog program value no longer contains a `Path` predicate symbol that can be referenced. We can evidence this by observing that the program:

``````def main(): Unit \ IO =
let db = #{
Edge(1, 2).
Edge(2, 3).
Edge(3, 1).
};
query db, cyclic() select (x, y) from Path(x, y) |> println
``````

prints the empty vector `Vector#{}` since `Path` has been made local by the predicate abstraction.