Pipes and Reverse Args
Calibre supports pipes, which let you pass a value into the next expression.
200 |> fn (s : dyn) => print("pipe closure => " & s);The value on the left of |> is fed into the expression on the right.
This is often easier to read than deeply nested function calls, especially when several steps happen in sequence.
You can also build up calls step by step.
const mul3 := fn (a b c : int) -> int => a * b * c;
let curried := 3 |> mul3 |> $(4);print(5 |> curried);In this example, 3 |> mul3 starts a call chain with the first argument. Then |> $(4) performs partial application by fixing another argument in place.
The $ is used to reference the result of the previous pipe segement, in the following case that result is a function therefore $ can be used to directly call that function.
So this creates a new function that still needs one more argument.
let curried := 3 |> mul3 |> $(4);When 5 |> curried runs, that final value is supplied and the call completes.
This makes partial application a convenient way to build specialized functions from more general ones.
Named piped segments give the piped value a temporary name inside the next stage other than the generic $.
40 |: forty > fn (x : int) => print(forty + x);You can combine named piped segments with partial application.
40 |: forty > adder_float(forty) |> $(80) |> fn (input : float) => print(input);Reverse arguments are another way to feed values into a call from the right side. This is especially useful when using template functions allowing you to include extra data other than that from the string.
const intro := fn (splits : list:<str>, inputs : list:<str>, extra : bool, extra2 : int) => { print(splits); print(inputs); print(extra); print(extra2);};
intro"Hello {name}" <(true, 10);