Functional Chains
The Backtick-Dot Operator
Section titled “The Backtick-Dot Operator”The backtick-dot operator transitions from a legacy command (byte-stream) to a functional range (line-stream).
functional_expr ::= '`' command '`' '.' method_chainmethod_chain ::= method_call ('.' method_call)*method_call ::= method_name ['(' args ')']A legacy command must be wrapped in backticks to enter functional mode. The dot immediately after the closing backtick begins the chain. Everything inside backticks is parsed as a standard shell command (with pipes, redirects, arguments).
`ls -la`.sort()`grep -r "error" src/`.filter(x => x.length > 0).take(10)`cat file.txt`.sort().map(x => x.toUpper())Pipeline Interaction
Section titled “Pipeline Interaction”POSIX pipes inside backticks work normally:
`cat log.txt | head -100`.filter(x => x.contains("WARN"))A functional chain’s output can feed into a POSIX pipe:
`ls -la`.filter(x => x.contains(".d")).sort() | wc -lA POSIX pipe can feed into a backtick expression:
cat server.log | `grep "ERROR"`.sort().unique()Parentheses
Section titled “Parentheses”Parentheses are optional when a method takes no arguments:
`ls`.sort # equivalent to `ls`.sort()`ls`.sort.take(5) # mix freelyWhen a method takes arguments, parentheses are required.
Stream Selection
Section titled “Stream Selection”By default, backtick expressions capture stdout. Named stream methods select which stream to use:
| Method | Description |
|---|---|
.stdout | Select stdout only (default, implicit) |
.stderr | Select stderr only |
.merge | Combine stdout and stderr into one stream |
.capture | Run once, return object with stdout, stderr, and exitCode |
`make`.stderr > errors.txt`make`.merge.filter(x => x.contains("error"))
let result = `make`.captureresult["exitCode"]result["stdout"]result["stderr"]Redirection
Section titled “Redirection”Standard POSIX redirections work with backtick expressions:
`ls -la` > files.txt # stdout to file`ls -la` >> log.txt # stdout append`cat < input.txt`.sort # stdin from fileLambda Syntax
Section titled “Lambda Syntax”Methods like map and filter accept lambdas:
# explicit single-param`ls`.filter(x => x.endsWith(".log"))
# multi-param (for reduce)[1, 2, 3, 4].reduce(0, (acc, x) => acc + x) # 10
# implicit lambda -- the parameter is always `a`[1, 2, 3].map(a + 10) # [11, 12, 13][1, 2, 3, 4].filter(a > 2) # [3, 4]`ls`.map("-> ${a}") # string interpolation in implicit lambdaWhen a method receives a non-lambda expression, it wraps it as a => <expr>. The implicit a shadows any outer variable with the same name.