Add docs for auto-currying.

This commit is contained in:
Stephen Chung
2020-07-29 22:43:57 +08:00
parent 1465ba2315
commit 8299adf95c
10 changed files with 178 additions and 80 deletions

View File

@@ -49,9 +49,13 @@ fn anon_fn_1001(x) { this.data -= x; }
fn anon_fn_1002() { print this.data; }
```
WARNING - NOT Closures
----------------------
Remember: anonymous functions, though having the same syntax as Rust _closures_, are themselves
**not** closures. In particular, they do not capture their running environment. They are more like
Rust's function pointers.
They do, however, _capture_ variable _values_ from their execution environment, unless the [`no_capture`]
feature is turned on. This is accomplished via [automatic currying][capture].

View File

@@ -0,0 +1,54 @@
Capture External Variables via Automatic Currying
================================================
Poor Man's Closures
-------------------
Since [anonymous functions] de-sugar to standard function definitions, they retain all the behaviors of
Rhai functions, including being _pure_, having no access to external variables.
The anonymous function syntax, however, automatically _captures_ variables that are not defined within
the current scope, but are defined in the external scope - i.e. the scope where the anonymous function
is created.
Variables that are accessible during the time the [anonymous function] is created can be captured,
as long as they are not shadowed by local variables defined within the function's scope.
The values captured are the values of those variables at the time of the [anonymous function]'s creation.
New Parameters For Captured Variables
------------------------------------
In actual implementation, this de-sugars to:
1. Keeping track of what variables are accessed inside the anonymous function,
2. If a variable is not defined within the anonymous function's scope, it is looked up _outside_ the function and in the current execution scope - where the anonymous function is created.
3. The variable is added to the parameters list of the anonymous function, at the front.
4. The current value of the variable is then [curried][currying] into the [function pointer] itself, essentially carrying that value and inserting it into future calls of the function.
Automatic currying can be turned off via the [`no_capture`] feature.
Examples
--------
```rust
let x = 40;
let f = |y| x + y; // current value of variable 'x' is auto-curried
// the value 40 is curried into 'f'
x = 1; // 'x' can be changed but the curried value is not
f.call(2) == 42; // the value of 'x' is still 40
// The above de-sugars into this:
fn anon$1001(x, y) { x + y } // parameter 'x' is inserted
let f = Fn("anon$1001").curry(x); // current value of 'x' is curried
f.call(2) == 42;
```

View File

@@ -28,3 +28,12 @@ let curried = curry(func, 21); // function-call style also works
curried.call(2) == 42; // <- de-sugars to 'func.call(21, 2)'
// only one argument is now required
```
Automatic Currying
------------------
[Anonymous functions] defined via a closure syntax _capture_ external variables that are not shadowed inside
the function's scope.
This is accomplished via [automatic currying].

View File

@@ -21,6 +21,18 @@ When a property of an [object map] is called like a method function, and if it h
a valid [function pointer] (perhaps defined via an [anonymous function]), then the call will be
dispatched to the actual function with `this` binding to the [object map] itself.
Use Anonymous Functions to Define Methods
----------------------------------------
[Anonymous functions] defined as values for [object map] properties take on a syntactic shape
that resembles very closely that of class methods in an OOP language.
Anonymous functions can also _capture_ variables from the defining environment, which is a very
common OOP pattern. Capturing is accomplished via a feature called _[automatic currying]_ and
can be turned off via the [`no_capture`] feature.
Examples
--------