# Function manipulation

Words provided by this unit allow treating words just as any other value, that
is, they can be created and returned on the fly. Such anonymous words are
referred here as lambdas.

## Lambda lifetime

Lambdas are very similar to anonymous words declared through ":>" in the sense
that you can compile an portion of code and get it back through an execution
token.

However, lambdas can be declared during both compilation and interpretation.
That means that an anonymous word can be created and returned inside of another
word. This implies that lambdas have a very different lifetime depending on
their creation context:
- in interpretation mode, a lambda is allocated in a rolling buffer
  (see [mem/scratch]) and has a temporary lifetime. If enough lambdas are
  created one can get overwritten and thus its xt point to a wrong place.
- in compilation mode, a lambda is directly embedded inside of the code it is
  created. It shares its lifetime from the word it lives in.
This is very similar to string pool and allocation, see [lib/str].

To make sure a temporary lambda is valid before executing it, its xt is embedded
before the actual code akin to a tag. This provides an easy way to check for
lambda validity with few false negatives.

In order to perform such check, use "valid#".
Assume that temporary lambdas are always invalidated after a unit load.

## Example usage

\ Lambdas work equally well during compilation and interpretation
: foo ( -- xt ) [: 7 * :] ; \ Return a lambda that multiplies by 7
2 foo execute . \ Prints "14"
[: ."hello " . 1+ nl> :] 3 timesi \ Prints "hello 1" "hello 2" "hello 3"

\ Lambdas can be nested
: bar ( -- xt ) [: 1 [: 1+ ."hello!" :] execute . :] ;
bar execute \ Prints "hello!2"

\ Data can be embedded inside of lambdas to have a state
[: [ 4 ] embed0 drop 1 over +! @ . :]
5 times \ Prints "12345"

\ Lambdas can be bound to values
[: * + :] ( l: a b c -- n )
4 5 rot 2 swap n>[:] ( l: a -- n )
8 over execute . \ Prints 5*4+8=28
3 swap execute . \ Prints 5*4+3=23

\ Binding can also be done through another lambda
[: * + :] ( l: a b c -- n )
[: ( b l ) 3 rot> 2 swap ( a b c l ) execute :] >[:] ( l: b -- n )
4 swap execute . \ Prints 2*4+3=11

## API

### Constants

LDASZ $100  The maximum allowed size in bytes of a temporary lambda. Going
            further will result in a warning but not an abort, as this can still
            work in some cases.

### Words

Note that "[:" and ":]" immediate signatures are bound to change and shouldn't
be relied upon yet.

[: ( -- aj al run: -- ) *I*
  Start compiling a new lambda.
  aj=0 when the lambda is being compiled in interpret mode.

:] ( aj al -- xt run: -- xt ) *I*
  Stop compiling a lambda and return its address.

nlitn ( ... n -- )
  Like litn but allows compiling calls to "n" literals at once instead of one.
  Noop when n=0 and same as litn when n=1.

nbind> ( ... n xt -- xt )
  Like bind> but allows binding "n" values instead of one.
  "0 nbind>" is noop. "1 nbind>" is the equivalent of bind>.

>[:] ( n xt -- xt )
n>[:] ( ... n xt -- xt )
  Like bind>/nbind> but return a temporary lambda instead.

valid# ( xt -- ) *A*
  Check whether a given temporary lambda hasn't been overwritten. Abort if the
  temporary lambda is considered invalid.

### Function manipulating words

Words below marked as *A* are only effectively *A* if "xt" is itself *A*.

times ( xt n -- xt: -- ) *A*
  Execute "xt" "n" times.

timesi ( xt n -- xt: u -- ) *A*
  Execute "xt" "n" times and give the 0-based index as an argument to xt.

some# ( ...? f -- ... ) *A*
  Assume that f=1, abort otherwise.

map[]  ( a u xt -- xt: n -- n ) *A*
cmap[] ( a u xt -- xt: c -- c ) *A*
  Applies "xt" onto each element of the range and write the result back to it.

reduce[]  ( a u xt -- n? f xt: acc n -- n )
creduce[] ( a u xt -- c? f xt: acc c -- c )
  Reduce an array to an element, that is, apply repeatedly "xt" to its
  elements until there is no element left. f=0 on empty ranges. For example:

  create data map< , 1 2 3 4
  data 4 ' + reduce[] \ Computes ((1+2)+3)+4=10
  data 4 ' max reduce[] \ Gets the maximum number in the range

fold[]  ( acc a u xt -- n xt: acc n -- n ) *A*
cfold[] ( acc a u xt -- c xt: acc c -- c ) *A*
  Fold an array to an element, that is, apply repeatedly "xt" to its elements
  starting from the given accumulator "acc". This word is very close to
  "reduce[]" but an initial accumulator is given. Return the accumulator
  unchanged on empty range.

  reduce[] is just a specialized fold[] where "acc" is its first element.

  create data map< , 1 2 3 4
  2 data ' * fold[] \ Computes (((2*1)*2)*3)*4=48

filter[]  ( a u xt -- a u xt: n -- f )
cfilter[] ( a u xt -- a u xt: c -- f )
  Filters a range according to a given predicate "xt". Only elements whose check
  returns true are kept. This modifies the range in place, meaning, "a" stays
  the same while "u" is smaller or equal than its original value.

  creata data map< , 1 2 3 4
  data 4 [: 1 and not :] filter[] \ Removes odd numbers

find[]  ( a u xt -- idx? f xt: n -- f ) *A*
cfind[] ( a u xt -- idx? f xt: c -- f ) *A*
  Return the index to the first element whose condition is verified by "xt".
  The elements are checked from left to right. f=0 if no match found.

rfind[]  ( a u xt -- idx? f xt: n -- f ) *A*
rcfind[] ( a u xt -- idx? f xt: c -- f ) *A*
  Similar to find[] but check elements from right to left.
