Revise doc for the builtin module.

- Revise the introduction section.

- Link to the notes on commands taking value inputs from all such commands.

- Revise the doc on the "all" command.

- Revise references to the builtin module from the language reference.
This commit is contained in:
Qi Xiao 2021-12-28 11:57:17 +00:00
parent 44e300095b
commit 7da4b58f2f
7 changed files with 156 additions and 101 deletions

View File

@ -66,9 +66,9 @@ func nsFn(m vals.Map) (*Ns, error) {
// make-map $input?
// ```
//
// Outputs a map from an input consisting of containers with two elements. The
// first element of each container is used as the key, and the second element is
// used as the value.
// Outputs a map from the [value inputs](#value-inputs), each of which must be
// an iterable value with with two elements. The first element of each value
// is used as the key, and the second element is used as the value.
//
// If the same key appears multiple times, the last value is used.
//

View File

@ -94,10 +94,10 @@ func runParallel(fm *Frame, functions ...Callable) error {
//elvdoc:fn each
//
// ```elvish
// each $f $input-list?
// each $f $inputs?
// ```
//
// Call `$f` on all inputs.
// Calls `$f` on each [value input](#value-inputs).
//
// An exception raised from [`break`](#break) is caught by `each`, and will
// cause it to terminate early.
@ -152,14 +152,14 @@ func each(fm *Frame, f Callable, inputs Inputs) error {
//elvdoc:fn peach
//
// ```elvish
// peach $f $input-list?
// peach $f $inputs?
// ```
//
// Calls `$f` on all inputs, possibly in parallel.
// Calls `$f` for each [value input](#value-inputs), possibly in parallel.
//
// Like `each`, an exception raised from [`break`](#break) will cause `peach`
// to terminate early. However due to the parallel nature of `peach`, the exact
// time of termination is non-deterministic and not even guaranteed.
// time of termination is non-deterministic, and termination is not guaranteed.
//
// An exception raised from [`continue`](#continue) is swallowed and can be used
// to terminate a single iteration early.

View File

@ -824,11 +824,11 @@ func fromTerminated(fm *Frame, terminator string) error {
//elvdoc:fn to-lines
//
// ```elvish
// to-lines $input?
// to-lines $inputs?
// ```
//
// Writes each value input to a separate line in the byte output. Byte input is
// ignored.
// Writes each [value input](#value-inputs) to a separate line in the byte
// output. Byte input is ignored.
//
// ```elvish-transcript
// ~> put a b | to-lines
@ -861,12 +861,14 @@ func toLines(fm *Frame, inputs Inputs) error {
//elvdoc:fn to-terminated
//
// ```elvish
// to-terminated $terminator $input?
// to-terminated $terminator $inputs?
// ```
//
// Writes each value input to the byte output with the specified terminator character. Byte input is
// ignored. This behavior is useful, for example, when feeding output into a program that accepts
// NUL terminated lines to avoid ambiguities if the values contains newline characters.
// Writes each [value input](#value-inputs) to the byte output with the
// specified terminator character. Byte input is ignored. This behavior is
// useful, for example, when feeding output into a program that accepts NUL
// terminated lines to avoid ambiguities if the values contains newline
// characters.
//
// The `$terminator` must be a single ASCII character such as `"\x00"` (NUL).
//

View File

@ -151,13 +151,13 @@ var eawkWordSep = regexp.MustCompile("[ \t]+")
//elvdoc:fn eawk
//
// ```elvish
// eawk $f $input-list?
// eawk $f $inputs?
// ```
//
// For each input, call `$f` with the input followed by all its fields. A
// [`break`](./builtin.html#break) command will cause `eawk` to stop processing
// inputs. A [`continue`](./builtin.html#continue) command will exit $f, but is
// ignored by `eawk`.
// For each [value input](#value-inputs), calls `$f` with the input followed by
// all its fields. A [`break`](./builtin.html#break) command will cause `eawk`
// to stop processing inputs. A [`continue`](./builtin.html#continue) command
// will exit $f, but is ignored by `eawk`.
//
// It should behave the same as the following functions:
//

View File

@ -27,38 +27,82 @@ func init() {
//elvdoc:fn all
//
// ```elvish
// all $input-list?
// all $inputs?
// ```
//
// Passes inputs to the output as is. Byte inputs into values, one per line.
// Takes [value inputs](#value-inputs), and outputs those values unchanged.
//
// This is an identity function for commands with value outputs: `a | all` is
// equivalent to `a` if it only outputs values.
// This is an [identity
// function](https://en.wikipedia.org/wiki/Identity_function) for the value
// channel; in other words, `a | all` is equivalent to just `a` if `a` only has
// value output.
//
// This function is useful for turning inputs into arguments, like:
// This command can be used inside output capture (i.e. `(all)`) to turn value
// inputs into arguments. For example:
//
// ```elvish-transcript
// ~> use str
// ~> put 'lorem,ipsum' | str:split , (all)
// ▶ lorem
// ▶ ipsum
// ```
//
// Or capturing all inputs in a variable:
//
// ```elvish-transcript
// ~> x = [(all)]
// foo
// bar
// (Press ^D)
// ~> put $x
// ~> echo '["foo","bar"] ["lorem","ipsum"]' | from-json
// ▶ [foo bar]
// ▶ [lorem ipsum]
// ~> echo '["foo","bar"] ["lorem","ipsum"]' | from-json | put (all)[0]
// ▶ foo
// ▶ lorem
// ```
//
// When given a list, it outputs all elements of the list:
// The latter pipeline is equivalent to the following:
//
// ```elvish-transcript
// ~> all [foo bar]
// ~> put (echo '["foo","bar"] ["lorem","ipsum"]' | from-json)[0]
// ▶ foo
// ▶ lorem
// ```
//
// In general, when `(all)` appears in the last command of a pipeline, it is
// equivalent to just moving the previous commands of the pipeline into `()`.
// The choice is a stylistic one; the `(all)` variant is longer overall, but can
// be more readable since it allows you to avoid putting an excessively long
// pipeline inside an output capture, and keeps the data flow within the
// pipeline.
//
// Putting the value capture inside `[]` (i.e. `[(all)]`) is useful for storing
// all value inputs in a list for further processing:
//
// ```elvish-transcript
// ~> fn f { var inputs = [(all)]; put $inputs[1] }
// ~> put foo bar baz | f
// ▶ bar
// ```
//
// The `all` command can also take "inputs" from an iterable argument. This can
// be used to flatten lists or strings (although not recursively):
//
// ```elvish-transcript
// ~> all [foo [lorem ipsum]]
// ▶ foo
// ▶ [lorem ipsum]
// ~> all foo
// ▶ f
// ▶ o
// ▶ o
// ```
//
// This can be used together with `(one)` to turn a single iterable value in the
// pipeline into its elements:
//
// ```elvish-transcript
// ~> echo '["foo","bar","lorem"]' | from-json
// ▶ [foo bar lorem]
// ~> echo '["foo","bar","lorem"]' | from-json | all (one)
// ▶ foo
// ▶ bar
// ▶ lorem
// ```
//
// When given byte inputs, the `all` command currently functions like
// [`from-lines`](#from-lines), although this behavior is subject to change:
//
// ```elvish-transcript
// ~> print "foo\nbar\n" | all
// ▶ foo
// ▶ bar
// ```
@ -80,14 +124,14 @@ func all(fm *Frame, inputs Inputs) error {
//elvdoc:fn one
//
// ```elvish
// one $input-list?
// one $inputs?
// ```
//
// Passes inputs to outputs, if there is only a single one. Otherwise raises an
// exception.
// Takes exactly one [value input](#value-inputs) and outputs it. If there are
// more than one value inputs, raises an exception.
//
// This function can be used in a similar way to [`all`](#all), but is a better
// choice when you expect that there is exactly one output:
// choice when you expect that there is exactly one output.
//
// @cf all
@ -109,13 +153,18 @@ func one(fm *Frame, inputs Inputs) error {
//elvdoc:fn take
//
// ```elvish
// take $n $input-list?
// take $n $inputs?
// ```
//
// Retain the first `$n` input elements. If `$n` is larger than the number of input
// elements, the entire input is retained. Examples:
// Outputs the first `$n` [value inputs](#value-inputs). If `$n` is larger than
// the number of value inputs, outputs everything.
//
// Examples:
//
// ```elvish-transcript
// ~> range 2 | take 10
// ▶ 0
// ▶ 1
// ~> take 3 [a b c d e]
// ▶ a
// ▶ b
@ -123,9 +172,6 @@ func one(fm *Frame, inputs Inputs) error {
// ~> use str
// ~> str:split ' ' 'how are you?' | take 1
// ▶ how
// ~> range 2 | take 10
// ▶ 0
// ▶ 1
// ```
//
// Etymology: Haskell.
@ -151,15 +197,19 @@ func take(fm *Frame, n int, inputs Inputs) error {
//elvdoc:fn drop
//
// ```elvish
// drop $n $input-list?
// drop $n $inputs?
// ```
//
// Drop the first `$n` elements of the input. If `$n` is larger than the number of
// input elements, the entire input is dropped.
// Ignores the first `$n` [value inputs](#value-inputs) and outputs the rest.
// If `$n` is larger than the number of value inputs, outputs nothing.
//
// Example:
//
// ```elvish-transcript
// ~> range 10 | drop 8
// ▶ (num 8)
// ▶ (num 9)
// ~> range 2 | drop 10
// ~> drop 2 [a b c d e]
// ▶ c
// ▶ d
@ -168,7 +218,6 @@ func take(fm *Frame, n int, inputs Inputs) error {
// ~> str:split ' ' 'how are you?' | drop 1
// ▶ are
// ▶ 'you?'
// ~> range 2 | drop 10
// ```
//
// Etymology: Haskell.
@ -251,8 +300,9 @@ func count(fm *Frame, args ...interface{}) (int, error) {
// order &reverse=$false $less-than=$nil $inputs?
// ```
//
// Outputs the input values sorted in ascending order. The sort is guaranteed to
// be [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
// Outputs the [value inputs](#value-inputs) sorted
// in ascending order. The sorting process is guaranteed to be
// [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
//
// The `&reverse` option, if true, reverses the order of output.
//

View File

@ -8,13 +8,20 @@ The builtin module contains facilities that are potentially useful to all users.
## Using builtin: explicitly
The builtin module is consulted implicitly when resolving unqualified names, so
you usually don't need to specify `builtin:` explicitly. However, there are some
cases where it is useful to do that:
The builtin module is consulted implicitly when
[resolving unqualified names](language.html#scoping-rule), and Elvish's
namespacing mechanism makes it impossible for other modules to redefine builtin
symbols. It's almost always sufficient (and safe) to use builtin functions and
variables with their unqualified names.
- When a builtin function is shadowed by a local function, you can still use
the builtin function by specifying `builtin:`. This is especially useful
when wrapping a builtin function:
Nonetheless, the builtin module is also available as a
[pre-defined module](language.html#pre-defined-modules). It can be imported with
`use builtin`, which makes all the builtin symbols available under the
`builtin:` namespace. This can be useful in several cases:
- To refer to a builtin function when it is shadowed locally. This is
especially useful when the function that shadows the builtin one is a
wrapper:
```elvish
use builtin
@ -24,7 +31,10 @@ cases where it is useful to do that:
}
```
- Introspecting the builtin module, for example `keys $builtin:`.
Note that the shadowing of `cd` is only in effect in the local lexical
scope.
- To introspect the builtin module, for example `keys $builtin:`.
## Usage Notation
@ -40,7 +50,7 @@ Optional arguments are represented with a trailing `?`, while variadic arguments
with a trailing `...`. For instance, the `count` command takes an optional list:
```elvish
count $input-list?
count $inputs?
```
While the `put` command takes an arbitrary number of arguments:
@ -58,29 +68,36 @@ echo &sep=' ' $value...
(When you calling functions, options are always optional.)
## Supplying Input
## Commands taking value inputs {#value-inputs}
Some builtin functions, e.g. `count` and `each`, can take their input in one of
two ways:
Most commands that take value inputs (e.g. `count`, `each`) can take the inputs
in one of two ways:
1. From pipe:
1. From the pipeline:
```elvish-transcript
~> put lorem ipsum | count # count number of inputs
2
~> put 10 100 | each [x]{ + 1 $x } # apply function to each input
▶ 11
▶ 101
~> put 10 100 | each {|x| + 1 $x } # apply function to each input
(num 11)
(num 101)
```
Byte pipes are also possible; one line becomes one input:
If the previous command outputs bytes, one line becomes one string input, as
if there is an implicit [`from-lines`](#from-lines) (this behavior is
subject to change):
```elvish-transcript
~> echo "a\nb\nc" | count # count number of lines
~> print "a\nb\nc\n" | count # count number of lines
▶ 3
~> use str
~> print "a\nb\nc\n" | each $str:to-upper~ # apply to each line
▶ A
▶ B
▶ C
```
1. From an argument -- an iterable value:
1. From an argument -- an iterable value:
```elvish-transcript
~> count [lorem ipsum] # count number of elements in argument
@ -90,7 +107,7 @@ two ways:
▶ 101
```
Strings, and in future, other sequence types are also possible:
Strings, and in future, other sequence types are also supported:
```elvish-transcript
~> count lorem
@ -98,13 +115,11 @@ two ways:
```
When documenting such commands, the optional argument is always written as
`$input-list?`. On the other hand, a trailing `$input-list?` always indicates
that a command can take its input in one of two ways above: this fact is not
repeated below.
`$inputs?`.
**Note**: You should prefer the first form, unless using it requires explicit
`put` commands. Avoid `count [(some-command)]` or
`each $some-func [(some-command)]`; they are, most of the time, equivalent to
`each $some-func [(some-command)]`; they are equivalent to
`some-command | count` or `some-command | each $some-func`.
**Rationale**: An alternative way to design this is to make (say) `count` take
@ -117,7 +132,7 @@ in the argument, even if there is no file.
## Numeric commands
Anywhere a command expects a number argument, that argument can be supplied
Wherever a command expects a number argument, that argument can be supplied
either with a [typed number](language.html#number) or a string that can be
converted to a number. This includes numeric comparison commands like `==`.
@ -145,7 +160,7 @@ integers or rationals), they will always output an exact number. Examples:
▶ (num 60/17)
```
If the condition above is not satisfied - i.e. when a numeric command is not
If the condition above is not satisfied -- i.e. when a numeric command is not
designated exactness-preserving, or when at least one of the arguments is
inexact (i.e. a floating-point number), the result is an inexact number, unless
otherwise documented. Examples:
@ -164,13 +179,7 @@ There are some cases where the result is exact despite the use of inexact
arguments or non-exactness-preserving commands. Such cases are always documented
in their respective commands.
## Predicates
Predicates are functions that write exactly one output that is either `$true` or
`$false`. They are described like "Determine ..." or "Test ...". See [`is`](#is)
for one example.
## "Do Not Use" Functions and Variables
## Unstable features
The name of some variables and functions have a leading `-`. This is a
convention to say that it is subject to change and should not be depended upon.

View File

@ -695,7 +695,8 @@ bar
```
If a variable is not in any of the lexical scopes, Elvish tries to resolve it in
the `builtin:` namespace, and if that also fails, fails with an error:
the [builtin namespace](builtin.html), and if that also fails, fails with an
error:
```elvish-transcript
~> echo $pid # builtin
@ -716,9 +717,6 @@ Compilation error: variable $nonexistent not found
[tty], line 1: echo pre-error; echo $nonexistent
```
You cannot create new variables in the `builtin:` namespace, although existing
variables in it can be assigned new values.
## Closure semantics
When a function literal refers to a variable in an outer scope, the function
@ -2362,11 +2360,6 @@ The following namespaces have special meanings to the language:
This **is** always needed, because unlike command resolution, variable
resolution does not fall back onto environment variables.
- `builtin:` refers to builtin functions and variables.
You don't need to use this explicitly unless you have defined names that
shadows builtin counterparts.
## Modules
Apart from the special namespaces, the most common usage of namespaces is to
@ -2417,8 +2410,9 @@ use a/b/c foo # imports the "a/b/c" module as "foo:"
Elvish's standard library provides the following pre-defined modules that can be
imported by the `use` command:
- [edit](edit.html) is only available in interactive mode. As a special case
it does not need importing via `use`, but this may change in the future.
- [builtin](builtin.html)
- [edit](edit.html): only available in interactive mode. As a special case it
does not need importing via `use`, but this may change in the future.
- [epm](epm.html)
- [math](math.html)
- [path](path.html)
@ -2427,7 +2421,7 @@ imported by the `use` command:
- [readline-binding](readline-binding.html)
- [store](store.html)
- [str](str.html)
- [unix](unix.html) is only available on UNIX-like platforms (see
- [unix](unix.html): only available on UNIX-like platforms (see
[`$platform:is-unix`](platform.html#platform:is-unix))
### User-defined modules