How do I use Function and Routine for transformations?
← Generics · Ref: Q710
Function and Routine are the two-type-parameter transformation types. They take 't' of type T and return 'r' of type R.
FUNCTION IS PURE
Function of (T, R) takes parameter 't' and returns 'r'. Being pure, the transformation is deterministic:
mapper <- () is Function of (String, Integer) as pure function r: length t
Always produces the same output for the same input.
ROUTINE IS IMPURE
Routine of (T, R) has the same signature but is NOT pure:
logMapper <- () is Routine of (String, Integer) as function stdout <- Stdout() stdout.println(`Transforming: ${t}`) r: length t
Routine allows side effects during transformation.
PARAMETER USAGE
Accept Function for guaranteed pure transforms:
transform() as pure -> item as String, mapper as Function of (String, Integer) <- result as Integer: mapper(item)
See Q54 for pure vs impure concepts. See Q89 for stream pipeline operations. See Q649 for generic function implementation.
Example
defines module qa.genericsdeep.functionroutine defines function <?- Helper that applies a pure Function transformation. -?> applyTransform() as pure -> item as String mapper as Function of (String, Integer) <- result as Integer: mapper(item) <?- Helper that applies an impure Routine transformation. -?> applyRoutine() -> item as String mapper as Routine of (String, Integer) <- result as Integer: mapper(item) defines program FunctionRoutineDemo() stdout <- Stdout() //Function: pure, deterministic transform //Body uses 't' for input, 'r' for return — from Function's signature lenMapper <- () is Function of (String, Integer) as pure function r: length t stdout.println(`Length of 'Hello': ${applyTransform("Hello", lenMapper)}`) //Another Function: Integer to String strMapper <- () is Function of (Integer, String) as pure function r: $t stdout.println(`42 as string: ${strMapper(42)}`) //Routine: impure, can log during transformation logMapper <- () is Routine of (String, Integer) as function stdout <- Stdout() stdout.println(`Transforming: ${t}`) r: length t result <- applyRoutine("World", logMapper) stdout.println(`Routine result: ${result}`)
Common mistakes
E05150 — Function is pure — dynamic functions extending Function must use 'as pure function', not just 'as function'. The compiler requires the purity of the implementation to match its pure super type. See ek9 -h E05150 for details.
Incorrect:
() is Function of (Integer, String) as function
Correct:
() is Function of (Integer, String) as pure function
Other ways to ask this
- What is the difference between Function and Routine in EK9?
- How do I create a Function of (String, Integer) for mapping?
- When should I use Routine instead of Function?
Coming from another language?
Java: java.util.function.Function<T,R> — no purity distinction, can have side effects. Kotlin: (T) -> R — no pure/impure variants. Rust: Fn(T) -> R (pure) vs FnMut(T) -> R (stateful). Go: func(T) R — no purity enforcement. C#: Func<T, TResult> — no purity concept. EK9: Function (pure, deterministic transform) vs Routine (impure, can access state) — compile-time enforced.
Keywords: function, pure, function-type, map, side-effect, routine, mapping, transform, generic, impure, two-parameter