A closure is a function to be used later, which uses some of the data currently available, packaged together. Enclosed, if you will.
So, in Listack terms, if you have a data stack, and a function to be used later that depends on the current state of some of the data, you package together the data with the function for later use. This is a closure of the function over the data. So, if you have a function that will depend on two data objects, you write:
rest_of_stack data1 data2 \.func 3 .enlist >block
which produces:
{data1 data2 .func}
When the later time finally arrives, you simply invoke the closure.
rest_of_stack {data1 data2 .func} .eval
We could even make a procedure to create closures. Note that most of the procedure is purely for error handling.
def: "make_closure" [Seq, Int]
{ # will make a closure over n data items and one sequence
dup < o # the closure can't contain fewer than no data items
iff {
drop drop
"Closures may not have a negative number of arguments" .set_err
exit
}
dup > (depth - 3) # must have enough items on the stack
iff {
drop drop
"Stack not deep enough for number of closure arguments" .set_err
exit
}
1 .+ .enlist >block # the actual closure: {d1 d2 d3 ... dn seq}
}
def: "make_closure" [Block, Int]
{ # could also be: \.eval swap 1 .+ .make_closure
swap >seq swap .make_closure
} # could have used dip instead
def: "make_closure" [Word, Int]
{ # a b \func .dip --> a func b
\>seq .dip .make_closure
} # could have just repeated the original definition, but where's the fun in that?
No comments:
Post a Comment
I reserve the right to remove egregiously profane or abusive comments, spam, and anything else that really annoys me. Feel free to agree or disagree, but let's keep this reasonably civil.