Hi Brian,

> Hi Brett!
>
> While you're reassembling, think of the advantages that this
> trick can give you. This kind of assignment can be useful for
> implementing what the C world calls static local variables.
>
> You can set a word to a literal string value, then append to
> that string to create a string accumulator. This allows you
> to build a string incrementally.
>
> You can set a word to a literal block and store values in it.
> This allows you to use a function like a Scheme closure, a
> function with values bundled in it, like OOP in reverse. This
> technique allows OOP-like programming with better control of
> your data because it is hidden inside the function. Look at
> http://www.bigfoot.com/~brian.hawley/rebol/require.r for an
> example of how this technique can make for bulletproof code.
>
> The most fun with this technique comes when you use compose
> to create your code blocks. For example, consider this:
>
>      f: func [key] [
>          table: make hash! [a "a" b "b"] table/:key
>      ]
>
> Trivial, true, but imagine that pattern with a much larger
> hash table, or a large binary value, or a dozen charsets for
> a parse process. You can't directly represent those values
> as literals - they get recreated every time. Do that in a
> function and the function gets really slow. But do this:
>
>      f: func [key] compose [
>          table: (make hash! [a "a" b "b"]) table/:key
>      ]
>
> and the hash table is only created once, right before the
> function is created. All calls to f then reference the now
> literal hash table, making for a very fast, memory efficient
> function.
>
> If you can use literal hash tables in a function, you can do
> one of the coolest tricks from the functional-language world,
> memoization. When you memoize a function, it remembers the
> results of the calls to the function, so that later calls of
> that value don't have to recalculate the result. You can even
> do this from the outside with a separate function, although
> REBOL's flexible args make the general case of that rather
> tricky (I'll work on it). Here's a one-arg memoize function:
>
> memoize: func ["One-arg memoize, kinda weak :(" 'f [word!]] [
>      set f func [x /local f saved res] compose [
>          f: (get f) saved: (make hash! [])
>          either res: select saved :x [first res] [
>              res: f x
>              append saved reduce [:x reduce [res]]
>              res
>          ]
>      ]
> ]
>
> I know, it looks awkward, but this can speed up functions
> that have to go through even worse trouble to calculate
> their values in the first place. It also helps with those
> that use deep self-recursion to calculate their values, as
> REBOL's stack space is quite limited.
>
> Fun stuff?
>
> Brian Hawley
>

I recently had to program something, that could have been
considered a special case. A few comments:

- wouldn't it be better to have an argument of type any-function!
?
- shouldn't f: (get f) be replaced with f: first (reduce [reduce
[:f]]) ?
- is Select general enough for this purpose ?
- I had to supply different results for equal, but not same values
of argument - what about that ?

Fun, indeed
    Ladislav

Reply via email to