Anonymous Functions in Uxntal
In the context of Uxntal, lambdas are unlabeled inline routines delimited by curlies, not unlike Postscript's anonymous procedures. A lambda block is jumped over, and a pointer to the start of the lambda is pushed to the top of the return stack. The body of the lambda can be unquoted with the STH2r and JSR2 opcodes.
#12 #34 { ADD JMP2r } STH2r JSR2
A lambda block is managed label definition which can be used with standard immediate opcodes. For example, to skip over a length of code:
.button LDZ #00 EQU ?{ will-not-eval }
A lambda can be used to store data inline, and ensure that the content is not inadvertenly run.
{ "hello } STH2r print-lambda
Under the hood, the lambda block writes the length to jump by, and that length can be read to get the length of the lambda block.
@print-lambda ( {str}* -- ) DUP2k #0002 SUB2 LDA2 ADD2 SWP2 &l ( -- ) LDAk .Console/write DEO INC2 GTH2k ?&l POP2 POP2 JMP2r
A higher-order function is a function that takes a function as an argument or returns one as a result. In the following example, the foreach routine is expecting a pointer to a series of bytes, and a pointer to a function to apply on each byte-long item in memory.
{ 01 02 03 04 05 } STH2r ;double foreach
The body of the double
function reads the value of a cell in
memory and writes a result equal to twice its value, and the body of the
foreach
function is merely applying a function to each cell in
memory.
@double ( addr* -- addr* ) STH2k LDAk DUP ADD STH2r STA JMP2r @foreach ( {bytes}* fn* -- bytes* ) ,&t STR2 DUP2k #0002 SUB2 LDA2 ADD2 SWP2 &l ( -- ) [ LIT2 &t $2 ] JSR2 INC2 GTH2k ?&l POP2 POP2 JMP2r
Consider that the whole double
function can equally be
inlined:
{ 01 02 03 04 05 } STH2r { STH2k LDAk DUP ADD STH2r STA JMP2r } STH2r foreach
As another demonstration of the same concept, we can inline a list of items, here's an implementation of Lisp's member function that returns the member in a list, or nil.
{ =cat =dog =bat } STH2r ;rat member
@member ( {items}* target* -- res/-1* ) ,&t STR2 DUP2k #0002 SUB2 LDA2 ADD2 SWP2 &l ( -- ) LDA2k [ LIT2 &t $2 ] EQU2 ?&found INC2 INC2 GTH2k ?&l POP2 ;nil &found NIP2 JMP2r
Lambdas can also be nested into one another, but remember, only the outermost layer of a nested lambda is evaluated at a time:
#01 { { "foo $1 } STH2r !print-lambda } STH2r JCN2
incoming uxntal syntax uxntal immediate drifblim