Mercury Functions

Functions are logic containers with no side effects other than those explicitly stated by the developer. They may take any combination of variables and provide any form of output the developer specifies.

Function Declaration Syntax

All functions must explicitly declare inputs and outputs using in[] and out[]:

// Basic function structure
fn functionName in[input_declarations] out[output_declarations] {
    // Function body
}

Input/Output Examples

// Function with no inputs/outputs
fn logHello in[] out[] {
    print("Hello world");
}

// Function with typed inputs/outputs
fn multiplyBy5 in[i32 x] out[i32 y] {
    x * 5 = y;
}

// Multiple inputs/outputs
fn vectorOp in[i32 a, i32 b] out[i32 sum, i32 product] {
    a + b = sum;
    a * b = product;
}

Function Calling

i32 value = 4;
i32 result;

// Calling a function
multiplyBy5 in[value] out[result];

// Nested function calls (output routing)
fn square in[i32 x] out[i32 y] {
    x * x = y;
}

i32 finalValue;
square in[multiplyBy5 in[value] out] out[finalValue];

Function Variable Scoping

Variables inside functions are sandboxed by default:

fn foo in[] out[] {
    i32 counter = 0;
    fn bar in[] out[] {
        counter++; // ERROR: counter is out of scope!
    }
}

To share variables, use explicit declarations:

fn foo in[] out[] {
    @shared i32 counter = 0;
    fn bar in[] out[] {
        counter++; // Legal, explicitly shared
    }
}

Function Rules

Comparison with Other Languages

JavaScript

// JavaScript surprise mutation
function foo() {
    let x = 0;
    function bar() { x++; }  
    bar();
    return x;  // x modified unexpectedly
}

Mercury eliminates this issue:

foo {
    i32 x = 0;
    bar {
        x++; // ERROR: x is not in scope
    }
    bar();
}

Rust

// Rust borrow checker issues
fn foo() {
    let mut x = 0;
    let bar = || x += 1;  
    bar();
}

Mercury simplifies ownership to:

foo {
    @mut i32 x = 0;
    bar {
        x++; // Allowed since x is @mut
    }
}

Function Chaining & Output Routing

Mercury allows direct routing of function outputs into another function's inputs using a special bracket syntax.

Function Chaining Explained

Function outputs can be directly routed to another function's inputs by omitting the output brackets:

// Standard function call:
foo in[] out[];

// Nested function call (output routing):
bar in[foo in[x] out] out[];

Key Rule: When you remove the [] from a function's out declaration, its output will be placed in the input block of the containing function call instead of creating its own output.

Complete Example:

fn double in[i32 num] out[i32 result] {
    num * 2 = result;
}

fn printNumber in[i32 val] out[] {
    print(val);
}

// Chained call:
printNumber in[double in[5] out] out[];

This executes double(5) and automatically passes the result to printNumber.

Type Safety

Chained outputs must match the expected input type exactly:

fn A out[i32] { ... }
fn B in[str] { ... }

B in[A out ] out[]; // COMPILE ERROR: i32 ≠ str

Mercury Advanced Function Routing

Partial Output Consumption

When a function returns multiple values but you only need specific ones:

Ignore Specific Outputs

// Function with multiple outputs
fn getData in[] out[i32 count, str name, f64 price] {
    // ... implementation ...
}

// Call while ignoring 'price'
i32 items;
str title;
getData in[] out[count=items, name=title, ~ignore_f64price];

Ignore All Except Specified

// Same function, only using 'name'
str productName;
getData in[] out[~var_ignore_except[name], name=productName];
SyntaxAlternativesPurpose
~ignore_i32var ~IGN_VN_, ~Vign_ Ignore specific output variable
~var_ignore_except[a,b] ~FVIWE_, ~VignEx_ Ignore all outputs except specified

Advanced Variable Routing

Direct Name Mapping

a simple example of a situation in which you'll use this

bar in[] out[a,b];

you want to route bar's outputs to foo. they have the same datatypes but different names oh no! what do i do if i want to route x to b and y to a? simply use a dataflow routing OR a explicit transfer statement like so

foo in[bar in[] bar out (a=y,b=x)]; 

As you can see here, we take a from bar and set the y input of foo to it. it's very simple. to indicate the statement, simply enclose it in a parenthesis to show the conversion statement, simular to how parenthesis are evaluated first in mathematics. this is one of the only uses of parenthesis in mercury.

Important Notes:

fn process in[i32 width, i32 height] out[] { /* ... */ }
fn getDims in[] out[i32 w, i32 h] { /* ... */ }

// Route outputs to inputs with different names
process in[getDims in[] out (width=h, height=w)] out[];

FlowMap Structures

FlowMap DimsToProcess {
    width = h,  // simular to getDims.h -> process.width in c++
    height = w  // essentially getDims.w -> process.height in c++
}

// Usage with FlowMap
process in[getDims in[] out via DimsToProcess] out[];

Important Notes:

simple example and syntax use