Language Guide
Functions

funcs

funcs are first-class citizens in Flowa, meaning they can be assigned to variables, passed as arguments, and returned from other funcs.

Defining funcs

Basic func

func greet(name) {
    return "Hello, " + name;
}
 
let result = greet("Alice");
print(result);  // "Hello, Alice"

Multiple Parameters

func add(a, b) {
    return a + b;
}
 
func multiply(x, y, z) {
    return x * y * z;
}
 
print(add(3, 4));           // 7
print(multiply(2, 3, 4));   // 24

No Return Value

func log_message(message) {
    print("[LOG] " + message);
}
 
log_message("Application started");

Return Statement

func is_even(n) {
    if (n % 2 == 0) {
        return true;
    }
    return false;
}
 
// Early return
func divide(a, b) {
    if (b == 0) {
        return null;  // Early return for error case
    }
    return a / b;
}

func as Values

Assigning to Variables

func double(x) {
    return x * 2;
}
 
let my_func = double;
print(my_func(5));  // 10

Passing as Arguments

func apply(fn, value) {
    return fn(value);
}
 
func square(x) {
    return x * x;
}
 
let result = apply(square, 5);
print(result);  // 25

Closures

funcs can capture variables from their surrounding scope:

func create_multiplier(factor) {
    func multiply(x) {
        return x * factor;  // Captures 'factor'
    }
    return multiply;
}
 
let double = create_multiplier(2);
let triple = create_multiplier(3);
 
print(double(5));  // 10
print(triple(5));  // 15

Counter Example

func create_counter() {
    let count = 0;
    
    func increment() {
        count = count + 1;
        return count;
    }
    
    return increment;
}
 
let counter = create_counter();
print(counter());  // 1
print(counter());  // 2
print(counter());  // 3

Recursive funcs

funcs can call themselves:

func factorial(n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}
 
print(factorial(5));  // 120

Fibonacci

func fibonacci(n) {
    if (n <= 1) {
        return n;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}
 
print(fibonacci(7));  // 13

Sum Array Recursively

func sum_array(arr, index) {
    if (index >= len(arr)) {
        return 0;
    }
    return arr[index] + sum_array(arr, index + 1);
}
 
let numbers = [1, 2, 3, 4, 5];
print(sum_array(numbers, 0));  // 15

Variable Scope

Global Variables

let global_var = "I'm global";
 
func access_global() {
    print(global_var);  // Can access
}
 
access_global();

Local Variables

func test_scope() {
    let local_var = "I'm local";
    print(local_var);
}
 
test_scope();
// print(local_var);  // ERROR - undefined

Shadowing

let x = "global";
 
func test_shadow() {
    let x = "local";  // Shadows global x
    print(x);  // "local"
}
 
test_shadow();
print(x);  // "global"

Higher-Order funcs

Map func

func map(arr, transform) {
    let result = [];
    let i = 0;
    
    while (i < len(arr)) {
        result = push(result, transform(arr[i]));
        i = i + 1;
    }
    
    return result;
}
 
func double(x) {
    return x * 2;
}
 
let numbers = [1, 2, 3, 4, 5];
let doubled = map(numbers, double);
print(doubled);  // [2, 4, 6, 8, 10]

Filter func

func filter(arr, predicate) {
    let result = [];
    let i = 0;
    
    while (i < len(arr)) {
        if (predicate(arr[i])) {
            result = push(result, arr[i]);
        }
        i = i + 1;
    }
    
    return result;
}
 
func is_even(x) {
    return x % 2 == 0;
}
 
let numbers = [1, 2, 3, 4, 5, 6];
let evens = filter(numbers, is_even);
print(evens);  // [2, 4, 6]

Reduce func

func reduce(arr, reducer, initial) {
    let result = initial;
    let i = 0;
    
    while (i < len(arr)) {
        result = reducer(result, arr[i]);
        i = i + 1;
    }
    
    return result;
}
 
func add(a, b) {
    return a + b;
}
 
let numbers = [1, 2, 3, 4, 5];
let sum = reduce(numbers, add, 0);
print(sum);  // 15

Anonymous funcs

While Flowa doesn't have arrow funcs, you can define funcs inline:

func apply_to_array(arr, fn) {
    let result = [];
    let i = 0;
    while (i < len(arr)) {
        result = push(result, fn(arr[i]));
        i = i + 1;
    }
    return result;
}
 
// Define func inline
let numbers = [1, 2, 3];
let squared = apply_to_array(numbers, func(x) {
    return x * x;
});

Practical Examples

User Validator

func validate_user(user) {
    if (type(user) != "hash") {
        return false;
    }
    
    if (!("name" in user) || !("email" in user)) {
        return false;
    }
    
    if (len(user["name"]) < 2) {
        return false;
    }
    
    if (!contains(user["email"], "@")) {
        return false;
    }
    
    return true;
}
 
let user1 = {"name": "Alice", "email": "alice@example.com"};
let user2 = {"name": "B", "email": "invalid"};
 
print(validate_user(user1));  // true
print(validate_user(user2));  // false

Retry Logic

func retry(fn, max_attempts) {
    let attempt = 0;
    
    while (attempt < max_attempts) {
        let result = fn();
        
        if (result != null) {
            return result;
        }
        
        attempt = attempt + 1;
        print("Retry attempt " + tostring(attempt));
    }
    
    return null;
}

func Composition

func compose(f, g) {
    func composed(x) {
        return f(g(x));
    }
    return composed;
}
 
func add_one(x) {
    return x + 1;
}
 
func double(x) {
    return x * 2;
}
 
let add_then_double = compose(double, add_one);
print(add_then_double(5));  // 12 ((5 + 1) * 2)

Best Practices

Single Responsibility

// Good - each func does one thing
func validate_email(email) {
    return contains(email, "@");
}
 
func validate_age(age) {
    return age >= 18 && age < 120;
}
 
func validate_user(user) {
    return validate_email(user["email"]) && 
           validate_age(user["age"]);
}

Meaningful Names

// Good
func calculate_total_price(items) {
    // ...
}
 
// Avoid
func calc(x) {
    // ...
}

Keep funcs Small

// Break complex funcs into smaller ones
func process_order(order) {
    validate_order(order);
    calculate_total(order);
    apply_discount(order);
    send_confirmation(order);
}

Next Steps