mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-25 00:48:56 +00:00
84 lines
3.6 KiB
Markdown
84 lines
3.6 KiB
Markdown
# DSL user-defined functions
|
|
|
|
As of Miller 5.0.0 you can define your own functions, as well as subroutines.
|
|
|
|
## User-defined functions
|
|
|
|
Here's the obligatory example of a recursive function to compute the factorial function:
|
|
|
|
GENMD_RUN_COMMAND
|
|
mlr --opprint --from data/small put '
|
|
func f(n) {
|
|
if (is_numeric(n)) {
|
|
if (n > 0) {
|
|
return n * f(n-1);
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
# implicitly return absent-null if non-numeric
|
|
}
|
|
$ox = f($x + NR);
|
|
$oi = f($i);
|
|
'
|
|
GENMD_EOF
|
|
|
|
Properties of user-defined functions:
|
|
|
|
* Function bodies start with `func` and a parameter list, defined outside of `begin`, `end`, or other `func` or `subr` blocks. (I.e. the Miller DSL has no nested functions.)
|
|
|
|
* A function (uniqified by its name) may not be redefined: either by redefining a user-defined function, or by redefining a built-in function. However, functions and subroutines have separate namespaces: you can define a subroutine `log` (for logging messages to stderr, say) which does not clash with the mathematical `log` (logarithm) function.
|
|
|
|
* Functions may be defined either before or after use -- there is an object-binding/linkage step at startup. More specifically, functions may be either recursive or mutually recursive.
|
|
|
|
* Functions may be defined and called either within `mlr filter` or `mlr put`.
|
|
|
|
* Argument values may be reassigned: they are not read-only.
|
|
|
|
* When a return value is not implicitly returned, this results in a return value of [absent-null](reference-main-null-data.md). (In the example above, if there were records for which the argument to `f` is non-numeric, the assignments would be skipped.) See also the [null-data reference page](reference-main-null-data.md).
|
|
|
|
* See the section on [Local variables](reference-dsl-variables.md#local-variables) for information on scope and extent of arguments, as well as for information on the use of local variables within functions.
|
|
|
|
* See the section on [Expressions from files](reference-dsl-syntax.md#expressions-from-files) for information on the use of `-f` and `-e` flags.
|
|
|
|
## User-defined subroutines
|
|
|
|
Example:
|
|
|
|
GENMD_RUN_COMMAND
|
|
mlr --opprint --from data/small put -q '
|
|
begin {
|
|
@call_count = 0;
|
|
}
|
|
subr s(n) {
|
|
@call_count += 1;
|
|
if (is_numeric(n)) {
|
|
if (n > 1) {
|
|
call s(n-1);
|
|
} else {
|
|
print "numcalls=" . @call_count;
|
|
}
|
|
}
|
|
}
|
|
print "NR=" . NR;
|
|
call s(NR);
|
|
'
|
|
GENMD_EOF
|
|
|
|
Properties of user-defined subroutines:
|
|
|
|
* Subroutine bodies start with `subr` and a parameter list, defined outside of `begin`, `end`, or other `func` or `subr` blocks. (I.e. the Miller DSL has no nested subroutines.)
|
|
|
|
* A subroutine (uniqified by its name) may not be redefined. However, functions and subroutines have separate namespaces: you can define a subroutine `log` which does not clash with the mathematical `log` function.
|
|
|
|
* Subroutines may be defined either before or after use -- there is an object-binding/linkage step at startup. More specifically, subroutines may be either recursive or mutually recursive. Subroutines may call functions.
|
|
|
|
* Subroutines may be defined and called either within `mlr put` or `mlr put`.
|
|
|
|
* Subroutines have read/write access to `$`-variables and `@`-variables.
|
|
|
|
* Argument values may be reassigned: they are not read-only.
|
|
|
|
* See the section on [local variables](reference-dsl-variables.md#local-variables) for information on scope and extent of arguments, as well as for information on the use of local variables within functions.
|
|
|
|
* See the section on [Expressions from files](reference-dsl-syntax.md#expressions-from-files) for information on the use of `-f` and `-e` flags.
|