Tap Operator
The &. operator calls f(value) but discards the return and propagates the
original value to the next step. It is the right place for logs, metrics, and
debug output in the middle of a pipeline without breaking the flow.
The most common form combines |> with &. in the same step: the pipe advances
the transformation, the tap only observes:
Tap between pipe stages; standalone tap on an array — observes without changing the value.
02-tap-side-effects.zolo
// Feature: Tap operator `&.`
// Syntax: `value &. f()` calls `f(value)` but RETURNS the original `value`.
// When to use: side effects (log, debug, metrics) in the middle of a
// pipeline without breaking the flow. It is the "spy" between `|>` pipes.
fn double(x: int) -> int {
return x * 2
}
fn add_one(x: int) -> int {
return x + 1
}
// Function used as tap — print is the effect, return is discarded.
fn log_step(x: int) -> int {
print(" [tap] x = {x}")
return x
}
// Pipeline with tap between steps — observes without changing.
let r = 5
|> double() &. log_step()
// 10
// prints 10, propagates 10
|> add_one() &. log_step()
// 11
// prints 11, propagates 11
|> double()
// 22
print("final = {r}")
// expected:
// [tap] x = 10
// [tap] x = 11
// final = 22
// Tap is useful to inspect array length in the middle of the pipeline.
fn show_len(arr: [int]) -> [int] {
print(" [len] {arr.len()}")
return arr
}
let nums = [1, 2, 3, 4, 5] &. show_len()
print(nums.len())
// expected:
// [len] 5
// 5
Gotcha: when using tap on arrays inside a
|>pipeline, prefer breaking the intermediate step into a variable and callingprint(arr)directly. Interpolating an array inside a string ("{arr}") displays the internal handle, not the elements.
See also