# 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.