# Queries as Functions

TypeQL function provides a way to create abstractions over existing data, allowing queries to be expressed at a higher level. They can live in your schema - as a "library" your database provides, or be specified in the **preamble** of a query using the `with` keyword.

A function accepts a tuple of concepts as arguments, and returns zero or more tuples of concepts as a result. The body of a function can be a pipeline consisting of any number of **read** stages.

Find mutual friends

```typeql
#!test[schema]
#{{
define
relation friendship, relates friend @card(0..2);
entity person, plays friendship:friend;
#}}
#!test[schema]
define
fun mutual_friends($p1: person, $p2: person) -> { person }:
match
    $f1 isa friendship, links (friend: $p1, friend: $pm);
    $f2 isa friendship, links (friend: $p2, friend: $pm);
return { $pm };
```

## [](#_arguments_returns)Arguments & returns

Function arguments & returns can be instances or values, but not types. The types of these concepts must be declared in the signature.

Integer division returns quotient & remainder for the dividend & divisor

```typeql
#!test[schema]
define
fun divide($dividend: integer, $divisor:integer) -> integer, integer:
match
 let $quotient = floor($dividend/$divisor);
 let $remainder = $dividend - $quotient * $divisor;
return first $quotient, $remainder;
```

A function can either return a single tuple of concepts, or a stream of tuples. For a stream return, the declaration is surrounded by curly braces `{…​}`. As in the example above, a function returning a single tuple must convert the stream output of the pipeline to a single tuple using either the `first` or the `last` modifiers.

### [](#_reduce_returns)Reduce returns

Functions can also return an aggregation over the stream output by the body, using the reduce return modifier.

Find the number of posts by a page

```typeql
#!test[schema]
#{{
define
relation posting, relates page, relates post;
entity page plays posting:page;
#}}
#!test[schema, rollback]
define
fun post_count($page: page) -> integer:
match
  $posting isa posting, links (posted: $page);
return count($posting);
```

`reduce` returns a single answer, since it aggregates all answers into one.

## [](#_cyclic_functions_tabling)Cyclic functions & tabling

TypeDB tables recursive functions to break cycles. This has implications on the best way to implement the recursion. The classic example is computing the transitive closure of a function. In a tabled setting, the following (left-recursive) formulation is more efficient.

```typeql
#!test[schema]
#{{
define
relation edge, relates from_, relates to;
entity node plays edge:from_, plays edge:to;
#}}
#!test[schema, rollback]
define
fun reachable($from: node) -> { node }:
match
    { # Base case
        $_ isa edge, links (from_: $from, to: $to);
    } or { # Recursive case
        let $mid in reachable($from);
        $_ isa edge, links (from_: $mid, to: $to);
    };
return { $to };
```

This will return \`node\`s in a breadth-first fashion.

## [](#_references)References

*   [Functions](../../../typeql-reference/functions/index.md)
    

[Query Clauses & Pipelining](../query-clauses/index.md) [Advanced: Invalid Patterns](../invalid-patterns/index.md)

[Edit on GitHub](https://github.com/typedb/typedb-docs/edit/3.x-development/core-concepts/modules/ROOT/pages/typeql/queries-as-functions.adoc) Edit this page on GitHub.