\n","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"We are excited to announce the support of varargs in Rel."}]},{"type":"p","children":[{"type":"text","text":"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, "},{"type":"text","text":"x...","code":true},{"type":"text","text":", which matches zero or more variables."}]},{"type":"p","children":[{"type":"text","text":"Varargs can be useful when writing generic relations for common utilities."}]},{"type":"p","children":[{"type":"text","text":"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."}]},{"type":"p","children":[{"type":"text","text":"When using varargs, keep in mind that the system needs to compute the "},{"type":"a","url":"https://docs.relational.ai/rel/primer/basic-syntax#arity-and-cardinality","title":null,"children":[{"type":"text","text":"arity"}]},{"type":"text","text":" of the passed arguments. For an overloaded relation, this should be a finite number of arities."}]},{"type":"p","children":[{"type":"text","text":"The Rel "},{"type":"a","url":"https://docs.relational.ai/rel/ref/lib/stdlib","title":null,"children":[{"type":"text","text":"Standard Library"}]},{"type":"text","text":" includes the relation "},{"type":"text","text":"first","code":true},{"type":"text","text":" that returns the first argument of "},{"type":"text","text":"R","code":true},{"type":"text","text":". It is defined using varargs as:"}]},{"type":"code_block","lang":"rel","value":"@inline\ndef first[R](x) = ∃(y... : R(x, y...))","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"In this way, the argument "},{"type":"text","text":"R","code":true},{"type":"text","text":" can have any arity:"}]},{"type":"code_block","lang":"rel","value":"def R = {(1, 2, 3); (4, 5, 6)}\ndef output = first[R]","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"Output:"}]},{"type":"html","value":"","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"This works even if "},{"type":"text","text":"R","code":true},{"type":"text","text":" contains tuples of various lengths and data types:"}]},{"type":"code_block","lang":"rel","value":"def R = {(1, 2, 3, 4); (\"foo\", \"bar\")}\ndef output = first[R]","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"Output:"}]},{"type":"html","value":"","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"Varargs work for point-wise definitions."}]},{"type":"p","children":[{"type":"text","text":"For instance, say you want to check whether two relations are the same. You can do that in a point-free manner by using "},{"type":"text","text":"equal","code":true},{"type":"text","text":" from the Rel Standard Library as:"}]},{"type":"code_block","lang":"rel","value":"// read query\n\ndef foo = {(1, 2); (3, 4)}\ndef bar = {(1, 3); (3, 4)}\n\ndef output = equal(bar, foo)","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"The output returns "},{"type":"text","text":"false","code":true},{"type":"text","text":", which is equivalent to a zero-arity relation."}]},{"type":"p","children":[{"type":"text","text":"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:"}]},{"type":"code_block","lang":"rel","value":"// read query\n\ndef foo = {(1, 2); (3, 4)}\ndef bar = {(1, 3); (3, 4)}\n\ndef output = foo(x...) and bar(x...) from x...","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"In this case, the second tuples from both relations are equal and therefore the output is "},{"type":"text","text":"true","code":true},{"type":"text","text":"."}]},{"type":"p","children":[{"type":"text","text":"The constant "},{"type":"text","text":"true","code":true},{"type":"text","text":" is equivalent to "},{"type":"text","text":"{()}","code":true},{"type":"text","text":", which is the zero-arity relation that contains the empty tuple."}]},{"type":"p","children":[{"type":"text","text":"Finally, say you want to find tuples and their arities that occur both in "},{"type":"text","text":"foo","code":true},{"type":"text","text":" and "},{"type":"text","text":"bar","code":true},{"type":"text","text":" relations, without determining in advance what those arities might be. Again, you can do this with varargs:"}]},{"type":"code_block","lang":"rel","value":"def foo = {(\"Tom\", 25); (\"Alice\", 34, 175); (\"Bob\", 20, 180)}\ndef bar = {(\"John\", 19, 185); (\"Bob\", 20, 180); (\"Tom\", 25)}\n\ndef output(n, x... in foo) {\n arity[(x...)] = n and bar(x...)\n}","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"Output:"}]},{"type":"html","value":"","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"While varargs are very useful for generalizing your code, relations with small arities that are normalized in "},{"type":"a","url":"https://docs.relational.ai/rel/concepts/graph-normal-form","title":null,"children":[{"type":"text","text":"Graph Normal Form"}]},{"type":"text","text":" are preferred. This helps with performance, readability, and correctness."}]}],"_content_source":{"queryId":"src/content/resources/varargs-in-rel.mdx","path":["resource","body"]}},"_content_source":{"queryId":"src/content/resources/varargs-in-rel.mdx","path":["resource"]}}}}};
globalThis.tina_info = tina;
})();
Varargs in Rel · RelationalAI
Check out
highlights
of RelationalAI
at
Snowflake's Data Cloud Summit 2024!
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 of the passed arguments. For an overloaded relation, this should be a finite number of arities.
The Rel Standard Library includes the relation first that returns the first argument of R. It is defined using varargs as:
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:
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:
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 are preferred. This helps with performance, readability, and correctness.