# Writing functions

Schema for the following examples

```typeql
#!test[schema, commit]
define
  entity content owns id;
  entity page sub content,
    owns page-id,
    owns name;
  entity profile sub page,
    owns username;
  entity user sub profile,
    owns phone,
    owns karma;

  attribute id value string;
  attribute page-id sub id;
  attribute username sub page-id;
  attribute name value string;
  attribute phone value string;
  attribute karma value double;
# Some extra just to test the snippets
fun f1($a: integer) -> integer:
match let $x = $a;
return first $x;

fun f2($a: integer) -> integer:
match let $x = $a;
return first $x;

fun scalar_fun($a: integer, $b: integer) -> integer:
match let $x = $a + $b;
return first $x;

fun tuple_fun($a: integer, $b: integer) -> integer, integer:
match let $x = $a + $b; let $y = $a - $b;
return first $x, $y;

fun stream_fun($a: integer, $b: integer) -> { integer, integer }:
match let $x = $a + $b; let $y = $a - $b;
return { $x, $y };
```

## [](#_syntax)Syntax

### [](#declaration)Declaring a function

Functions in TypeQL are declared using the keyword `fun`. A function declaration consists of:

*   A function **signature** which itself consists of:
    
    *   A function name.
        
    *   Typed **input arguments** (optional).
        
    *   A **return type**.
        
    
*   A [read pipeline](../../pipelines/index.md#pipeline_kinds) as the **function body**.
    
*   A **return statement** that produces results of the specified return type.
    

Function Declaration Syntax

```typeql
fun <function-name> ( <optional-arguments> ) -> <return-types>:
<read_pipeline>
return <return-statement>
```

*   `<function-name>` is a valid label (i.e. a not reserved keyword or a TypeQL [literal](../../expressions/literals/index.md)).
    
*   `<optional-arguments>` is a list of zero of more typed variables, written in the format `$a : A, $b : B, …​`
    
*   `<return-types>` consists of at least one `<return-type>` and can be:
    
    *   a [stream](../stream/index.md) tuple type, written in the format `{ A, B, …​ }`.
        
    *   a [tuple](../scalar/index.md) type, written in the format `A, B, …​`.
        
    
    The types `A, B, …​` above can be either user-defined types (e.g. an entity type `user`) or primitive value types (e.g. `boolean`).
    
*   `<read_pipeline>` includes any read [pipeline](../../pipelines/index.md).
    
*   `<return-statement>` may consist of variables, [function calls](../../expressions/function-calls/index.md), and built-in reductions:
    
    *   Scalar return statements are of the form `$a;`.
        
    *   Tuple return statements are of the form `$a, $b, <built-in-reduction>, scalar_fun($c), …​;` (see [reduce](../../pipelines/reduce/index.md) for available built-in reductions).
        
    *   Stream return statements are of the form `{ $a, $b, scalar_fun($c), …​ };`.
        
    
    **Positions matter!** Returns of functions are assigned by position.
    

### [](#calling)Calling a function

Function Calling Syntax

```typeql
<function-name>(<arguments>)
```

`<arguments>` to a function call are of the form `$a, $b, …​`. They are always **variables** (and not expressions).

Function can be called:

1.  as part of an [expression](../../expressions/index.md). For example:
    
    Scalar expression comparison
    
    ```typeql
    #!test[read, count = 1]
    #{{
    match let $x = 0 ; let $y = 1;
    #}}
    $x + 1 < f1($y) + f2($y);
    ```
    
    Scalar expression assignment
    
    ```typeql
    #!test[read, count = 1]
    #{{
    match let $a = 0 ; let $b = 1;
    #}}
    let $x = scalar_fun($a, $b) / 2;
    ```
    
2.  as part of a tuple or stream assignment, for example:
    
    Tuple assignment
    
    ```typeql
    #!test[read, count = 1]
    #{{
    match let $a = 0 ; let $b = 1;
    #}}
    let $x, $y = tuple_fun($a, $b);
    ```
    
    Stream assignment
    
    ```typeql
    #!test[read, count = 1]
    #{{
    match let $a = 0 ; let $b = 1;
    #}}
    let $x, $y in stream_fun($a, $b);
    ```
    

## [](#_usage)Usage

### [](#_ambiguity)Ambiguity

Every function should have a unique name. It’s not allowed to declare two functions with the same name even if they have totally different arguments and return types.

### [](#query_level_functions)Using Functions at Query-Level

Functions can be defined temporarily at the query level using the `with` clause, becoming a [with pipeline stage](../../pipelines/with/index.md). Such functions exist only for the duration of the query and are not persisted in the database.

Multiple `with` clauses can be used, each defining a single function. All `with` clauses must precede the query pipeline.

Querying with Functions

```typeql
with <f1-declaration>
with <f2-declaration>
...
with <fN-declaration>
match
  $f1 = f1();
  $f2 = f2();
  ...
  $fN = fN();
```

For example, the following read pipeline defines and uses a temporary function using the `with` clause:

```typeql
#!test[read]
with fun karma_with_squared_value($user: user) -> karma, double:
  match
    $user has karma $karma;
    let $karma-squared = $karma * $karma;
  return first $karma, $karma-squared;

match
  $user isa user, has username $name;
  let $karma, $karma-squared = karma_with_squared_value($user);
select $name, $karma-squared;
```

### [](#_using_functions_in_definition_queries)Using Functions in definition queries

#### [](#_define)Define

In addition to [temporary query-level functions](#query_level_functions), functions can be persisted in schemas. Replace the keyword `with` with `define` and execute the query in a schema transaction:

```typeql
#!test[schema, commit]
define
  fun karma_with_squared_value($user: user) -> karma, double:
    match
      $user has karma $karma;
      let $karma-squared = $karma * $karma;
    return first $karma, $karma-squared;
```

Once persisted, these functions can be called directly in read queries:

```typeql
#!test[schema]
match
  $user isa user, has username $name;
  let $karma, $karma-squared = karma_with_squared_value($user);
select $name, $karma-squared;
```

#### [](#_redefine)Redefine

Everything except for the function name can be redefined using redefine queries.

```typeql
#!test[schema]
redefine
  fun karma_with_squared_value($karma: karma) -> double:
    match
      let $karma-squared = $karma * $karma;
    return first $karma-squared;
```

#### [](#_undefine)Undefine

To undefine a function, specify the `fun` keyword and its name.

```typeql
#!test[schema]
undefine
  fun karma_with_squared_value;
```

## [](#_learn_more)Learn More

[Data pipelines](../../pipelines/index.md)

Learn more about function bodies - pipelines.

[Stream functions](../stream/index.md)

Understand how to work with stream functions.

[Scalar and tuple functions](../scalar/index.md)

Explore single functions and their usage.

[Functions](../index.md) [Streams](../stream/index.md)

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