Memoizing functionsOften a few key values that rarely change cascade into a tree of calculated parameters. Accessing one of these functions is much slower than accessing a constant because of all of the redundant calculations. One way to speed things up is to cache these parameters and then do an update only after a function upon which they depend changes. 1 constant simple \ which kind of syntax to demonstrate
variable memos 0 memos ! \ list of memoized functions
variable memo> 0 memo> ! \ forward link
\ list: >link--\ >link 'p xt
\ memos ---^ \-------^
\ memo> -----------------^
\ The slightly more wordy syntax: :NONAME width height * ; MEMO area
\ This syntax is easier to implement and doesn't need EVALUATE.
: MEMO ( xt <name> - ) \ create a memoized function
create dup execute here >r ,
memo> @ if here memo> @ ! \ resolve forward link
else here memos !
then here memo> ! 0 , \ mark next forward link
, r> , does> @ ; \ data: xt 'param
simple [IF]
\ The simple syntax: MEMO: area width height * ;
\ This syntax requires the semantics of ; to be appended, which is usually
\ not an issue.
create memoevs char M c, char E c, char M c, char O c, bl c,
here 64 chars allot constant memoname \ evaluation string: "MEMO xxxxx"
variable memolen 0 memolen ! \ length of eval string
: MEMO: ( <name> - )
bl word count >r memoname r@ move r> 5 + memolen !
:noname ;
: ; ( - )
postpone ; memolen @ ?dup if
memoevs swap evaluate
0 memolen !
then ; immediate
[THEN]
: MEMO-UPDATE ( - ) \ update memoized functions
memos @ begin dup while
dup cell+ 2@ execute swap ! @ repeat drop ;
example 1 value one 2 value two simple [IF] MEMO: three one two + ; MEMO: four three 1+ ; MEMO: width three 2* ; MEMO: height four two + ; MEMO: area width height * ; [ELSE] :noname one two + ; MEMO three :noname three 1+ ; MEMO four [THEN] cr .( Should be 4: ) four . 3 to one \ change some primary values 4 to two memo-update \ update all memo functions cr .( Should be 8: ) four . |