[REBOL] Re: Fun with literal blocks!
From: lmecir:geocities at: 28-Oct-2000 9:03
Hi Joel,
> If you mean
>
> "Should Fibon be written as self-modifying code?"
>
> then (see my answer to Ladislav's comments on the same post) I'd answer
> that there are certainly some pros and cons to SMC. It is certainly a
> technique that should be used with care. OTOH, there are some very
> elegant things that can be done with functions that either:
>
> * maintain persistent state via SMC (less overhead vs full-blown objects),
I think, that you are mixing two issues here. One is a use of SMC and the
second one is the ability of a function to maintain its state or to do other
useful things...
The most general version of the state-maintaining technique is a possibility
to create a function having static local variables. Here are my 3
implementations of
that:
; 1) this version of Sfun creates a function having static local variables
; using an embedded object to maintain its state
sfun: function [
{Create a function with static local variables}
init [block!]
args [block!]
body [block!]
] [ini] [
ini: make-object init
body: compose [
(ini)
(bind/copy :body in ini 'self)
]
func :args :body
]
; a Make Object! modification allowing any Self
make-object: function [
{make object}
blk [block!] "object spec"
] [result getres] [
getres: func [value] [result: :value]
blk: compose [(:getres) :self (blk)]
error? make object! copy/deep blk
result
]
{
Example #1:
counter: sfun [self: 0] [] [
self: self + 1
print self
]
counter
counter
recycle
counter
Example #2
cell: func [
{create a function that holds a value}
initval [any-type!]
] [
sfun [value: none set/any 'value get/any 'initval origset: :set] [
/set newval [any-type!]
] [
either set [origset/any 'value get/any 'newval] [
get/any 'value
]
]
]
a: cell 5
print a
a/set 18
print a
Example #3
cell: func [
{create a function that holds a value}
require-type [datatype!]
initval [any-type!]
/local result
] [
result: sfun [value: none origset: :set] [
/set newval [require-type]
] [
either set [origset/any 'value get/any 'newval] [
get/any 'value
]
]
result/set get/any 'initval
:result
]
a: cell 5
print a
a/set 18
print a
}
; 2) this version of Sfun uses a Use technique,
; is *much* more elegant, totally WYSIWYG,
; it doesn't always have a static local 'Self as opposed to 1),
; but the GC bug doesn't allow it to work sometimes :(
; I wrote it to show, that the only reason
; for using a SMC technique
; may be to circumvent the GC bug
; (out of a frying pan and into the fire)
sfun: function [
{Create a function with static local variables}
init [block!]
args [block!]
body [block!]
] [words] [
words: make block! 0
foreach elem init [
if set-word? get/any 'elem [
append words to word! :elem
]
]
use union words [] copy/deep reduce [
:do :init
:func :args :body
]
]
{
Example #1:
counter: sfun [self: 0] [] [
self: self + 1
print self
]
counter
counter
counter
counter
}
; 3) this version creates an object behaving like
; a function having static local variables,
; the code is totally WYSIWYG too,
; and the GC bug doesn't have a chance:
sfun: func [
{Create a function with static local variables}
init [block!]
args [block!]
body [block!]
] [
make-object [
ini: make-object init
do: func args bind/copy body in ini 'self
]
]
{
Example #1:
counter: sfun [self: 0] [] [
self: self + 1
print self
]
counter/do
counter/do
recycle
counter/do
}
> * construct and then evaluate code blocks "on the fly", or
> * can examine (and modify) their own operation for explanation or
> optimization.
>
> The whole history of AI is full of examples of the latter two.
Just a comment:
my definition of SM/WYSIWYG Code is *much weeker*, than a "normal" one. That
means, that you *can* use a Rebol WYSIWYG code to construct and then
evaluate code blocks "on the fly". Similarly it is possible to examine and
modify the operation of functions. E.g. the code:
code: [
a: copy [1 remove a 2]
do copy a
]
is WYSIWYG according to the defininion I supplied.