expression is pure (true). Otherwise it is impure. The type and effect system allows arbitrary boolean expressions to control the purity of function arguments. For example, it is possible to express a higher-order function h that accepts two function arguments f and g of which at most one is impure: def h(f: a -> b & e1, g: b -> c & (not e1 or e2)): Unit If h is called with a function argument f which is impure (false) then the second argument must be pure (true). Conversely, if f is pure (true) then g may be pure (true) or impure (false). It is a compile-time error to call h with two impure functions. The type and effect system can be used to ensure that statement expressions are useful, i.e. that if an expression or function is evaluated and its result is discarded then it must have a side-effect. For example, compiling the program fragment below: def main(): Unit & Impure = List.map(x -> 2 * x, 1 :: 2 :: Nil); Console.printLine("Hello World") causes a compiler error: -- Redundancy Error -------------------------------------------------- >> Useless expression: It has no side-effect(s) and its result is discarded. 2 | List.map(x -> 2 * x, 1 :: 2 :: Nil); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ useless expression. because it is non-sensical to evaluate the pure expression List.map(x -> 2 * x, 1 :: 2 :: Nil) and then to discard its result. Most likely the programmer wanted to use the result (or alternatively the expression is redundant and could be deleted). Consequently, Flix rejects such programs. First-class datalog constraints Flix supports Datalog programs as first-class values. A Datalog program is a logic program that consists of a collection of unordered facts and rules. Together, the facts and rules imply a minimal model, a unique solution to any Datalog program. In Flix, Datalog program values can be passed to and returned from functions, stored in data structures, composed with other Datalog program values, and solved. The solution to a Datalog program (the minimal model) is itself a Datalog program. Thus, it is possible to construct pipelines of Datalog programs where the solution, i.e. "output", of one Datalog program becomes the "input" to another Datalog program. The following edge facts define a graph: Edge(1, 2). Edge(2, 3). Edge(3, 4). The following Datalog rules compute the transitive closure of the edge relation: Path(x, y) :- Edge(x, y). Path(x, z) :-