Varargs in Rel
We are excited to announce the support of varargs in Rel.
You can use varargs to write more general code that works for multiple arities. A vararg is written by appending three dots to a variable name, for instance, x...
, which matches zero or more variables.
Varargs can be useful when writing generic relations for common utilities.
For instance, say you want to define a relation that contains tuples of differing arities. Instead of overloading its declaration several times, you can simply use varargs.
When using varargs, keep in mind that the system needs to compute the arity (opens in a new tab) of the passed arguments. For an overloaded relation, this should be a finite number of arities.
The Rel Standard Library (opens in a new tab) includes the relation first
that returns the first argument of R
. It is defined using varargs as:
@inline
def first[R](x) = ∃(y... : R(x, y...))
In this way, the argument R
can have any arity:
// read query
def R = {(1, 2, 3); (4, 5, 6)}
def output = first[R]
Output:
This works even if R
contains tuples of various lengths and data types:
// read query
def R = {(1, 2, 3, 4); ("foo", "bar")}
def output = first[R]
Output:
Varargs work for point-wise definitions.
For instance, say you want to check whether two relations are the same. You can do that in a point-free manner by using equal
from the Rel Standard Library as:
// read query
def foo = {(1, 2); (3, 4)}
def bar = {(1, 3); (3, 4)}
def output = equal(bar, foo)
The output returns false
, which is equivalent to a zero-arity relation.
Now, let’s check whether there is a tuple that is contained in both relations. For that, you can use varargs using point-wise syntax as follows:
// read query
def foo = {(1, 2); (3, 4)}
def bar = {(1, 3); (3, 4)}
def output = foo(x...) and bar(x...) from x...
In this case, the second tuples from both relations are equal and therefore the output is true
.
The constant true
is equivalent to {()}
, which is the zero-arity relation that contains the empty tuple.
Finally, say you want to find tuples and their arities that occur both in foo
and bar
relations, without determining in advance what those arities might be. Again, you can do this with varargs:
// read query
def foo = {("Tom", 25); ("Alice", 34, 175); ("Bob", 20, 180)}
def bar = {("John", 19, 185); ("Bob", 20, 180); ("Tom", 25)}
def output(n, x... in foo) {
arity[(x...)] = n and bar(x...)
}
Output:
While varargs are very useful for generalizing your code, relations with small arities that are normalized in Graph Normal Form (opens in a new tab) are preferred. This helps with performance, readability, and correctness.
Related Posts
Value Types in Rel
Value types help distinguish between different types of values, even though the underlying representation may be identical. Value types can be used to define other value types.
Asynchronous Transactions: Start Now, Check Later
RelationalAI's full suite of SDKs provides access to API endpoints which allow you to track long-running transactions in our Relational Knowledge Graph Management System (RKGMS). This is more reliable for long-running transactions, allows transactions to be canceled, and keeps a log of transactions that you can inspect either while they're running or at a later time.