Functions are reusable blocks of code that perform specific tasks.
Use the fun keyword to define a function:
fun greet(name) {
print("Hello, " + name);
}
fun functionName(parameter1, parameter2) {
// Function body
print(parameter1, parameter2);
}
- Function name: Used to call the function later
- Parameters: Values passed to the function (optional)
- Function body: Code that runs when the function is called
Call a function using its name with parentheses:
fun greet(name) {
print("Hello, " + name);
}
greet("Alice"); // Output: Hello, Alice
greet("Bob"); // Output: Hello, Bob
Functions can accept multiple parameters:
fun add(a, b) {
print(a + b);
}
add(5, 3); // Output: 8
add(10, 20); // Output: 30
Parameters are local to the function:
fun test(x) {
x = 100;
print("Inside function:", x);
}
var x = 50;
test(x);
print("Outside function:", x); // x is still 50
Output:
Inside function: 100
Outside function: 50
Functions can return values using the return keyword:
fun add(a, b) {
return a + b;
}
var result = add(5, 3);
print(result); // Output: 8
Return can appear multiple times in a function:
fun max(a, b) {
if (a > b) {
return a;
}
return b;
}
print(max(10, 20)); // Output: 20
If a function doesn't explicitly return a value, it returns nil:
fun noReturn() {
print("This function has no return");
}
var result = noReturn();
print(result); // Output: nil
In Pome, functions are first-class values. You can assign them to variables:
fun add(a, b) {
return a + b;
}
var operation = add;
print(operation(5, 3)); // Output: 8
Pome supports anonymous function expressions, also known as lambdas. These functions don't have a name and can be assigned to variables or passed as arguments.
var multiply = fun(a, b) {
return a * b;
};
print(multiply(4, 5)); // Output: 20
You can assign function literals directly to variables:
var square = fun(x) {
return x * x;
};
print(square(5)); // Output: 25
Functions in Pome form closures, meaning they capture and retain access to variables from their defining scope, even after the outer function has returned.
fun makeAdder(amount) {
return fun(x) {
return x + amount;
};
}
var addFive = makeAdder(5);
print(addFive(10)); // Output: 15
var addTen = makeAdder(10);
print(addTen(10)); // Output: 20
Closures are useful for maintaining private state:
fun makeCounter() {
var count = 0;
return fun() {
count = count + 1;
return count;
};
}
var counter = makeCounter();
print(counter()); // Output: 1
print(counter()); // Output: 2
print(counter()); // Output: 3
Each call to makeCounter() creates a new count variable with its own closure.
Functions that take other functions as parameters or return them are called higher-order functions.
fun apply(operation, a, b) {
return operation(a, b);
}
fun add(a, b) {
return a + b;
}
fun multiply(a, b) {
return a * b;
}
print(apply(add, 5, 3)); // Output: 8
print(apply(multiply, 5, 3)); // Output: 15
You can pass anonymous functions directly as callbacks:
fun repeatTimes(count, callback) {
for (var i = 0; i < count; i = i + 1) {
callback(i);
}
}
repeatTimes(3, fun(i) {
print("Iteration", i);
});
Output:
Iteration 0
Iteration 1
Iteration 2
Variables declared inside a function are local to that function:
fun test() {
var local = "I'm local";
}
test();
print(local); // Error: undefined variable 'local'
Functions can access variables from outer scopes (lexical scoping):
var global = "I'm global";
fun test() {
print(global); // Can access global
}
test(); // Output: I'm global
Pome doesn't support default parameters directly, but you can work around it:
fun greet(name) {
var actualName = name;
if (actualName == nil) {
actualName = "Guest";
}
print("Hello, " + actualName);
}
greet("Alice"); // Output: Hello, Alice
greet(nil); // Output: Hello, Guest
greet(); // Error: expected 1 argument, got 0
Pome doesn't have built-in variadic function support, but you can pass lists:
fun sum(numbers) {
var total = 0;
for (var i = 0; i < len(numbers); i = i + 1) {
total = total + numbers[i];
}
return total;
}
print(sum([1, 2, 3, 4, 5])); // Output: 15
Functions can call themselves:
fun factorial(n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
print(factorial(5)); // Output: 120
Pome doesn't optimize tail calls, so deep recursion may cause issues:
fun countdown(n) {
if (n <= 0) {
print("Blastoff!");
return;
}
print(n);
countdown(n - 1);
}
countdown(3);
Output:
3
2
1
Blastoff!
Functions in Pome are first-class citizens, meaning they can be assigned to variables, passed as arguments, and returned from other functions.
When a function is defined inside another function, it can "capture" variables from the outer scope. This is called a closure.
fun makeCounter() {
var count = 0;
fun counter() {
count += 1;
return count;
}
return counter;
}
var c1 = makeCounter();
print(c1()); // Output: 1
print(c1()); // Output: 2
var c2 = makeCounter();
print(c2()); // Output: 1 (Separate state from c1)
- Lexical Scoping: Pome uses lexical scoping. A function can access variables defined in its surrounding scope at the time it was defined.
- Capture by Reference: Variables are captured by reference. If the outer variable changes, the closure sees the updated value.
- Persistent State: Captured variables persist as long as the closure exists, even after the outer function has finished executing.
You can define functions without a name:
var square = fun(x) {
return x * x;
};
print(square(5)); // Output: 25
Anonymous functions are often used as callbacks:
fun execute(fn, val) {
return fn(val);
}
print(execute(fun(x) { return x + 10; }, 5)); // Output: 15
-
Use meaningful names:
calculateTotalis better thancalc -
Keep functions focused: A function should do one thing well
// Good fun getUsername(user) { return user.name; } fun formatGreeting(name) { return "Hello, " + name; } // Less good fun processUser(user) { var name = user.name; var greeting = "Hello, " + name; print(greeting); return name; } -
Document complex logic: Use comments for non-obvious code
// Fibonacci using dynamic programming (avoiding deep recursion) fun fib(n) { if (n <= 1) return n; // ... implementation } -
Use closures wisely: They're powerful but can be hard to follow
// Clear closure usage var operations = { add: fun(a, b) { return a + b; }, subtract: fun(a, b) { return a - b; } }; -
Avoid deeply nested functions: Can impact readability
// Prefer fun outer() { var innerFunc = fun() { return 42; }; return innerFunc(); } // Over fun outer() { return (fun() { return (fun() { return 42; })(); })(); }
Next: Object-Oriented Programming
Back to: Documentation Home