I'm trying to create a dispatcher of functions in Rebol 3, so that for each string the program receives there's an associated function to be called.
For example:
handlers: make map! [
"foo" foo-func
"bar" bar-func
]
where foo-func
and bar-func
are functions:
foo-func: func [ a b ] [ print "foo" ]
bar-func: func [ a b ] [ print "bar" ]
The idea is to select
the function starting from the string, so:
f: select handlers "foo"
so that executing f
is the same as executing foo-func
and then call f
with some arguments:
f param1 param2
I tried quoting the words in the map!
, or using get-words but without success.
Using a get-word!
at the console, without passing through a map!
it works:
>> a: func [] [ print "Hello world!" ]
>> a
Hello world!
>> b: :a
>> b
Hello world!
Any help appreciated.
select handlers "foo"
only get the word foo-func
:
f: select handlers "foo"
probe f ;will get: foo-func
You need to get its content:
f: get f
f 1 2 ;will print "foo"
Or more compact:
f: get select handlers "foo"
It's better to actually have the reference to the function in the map, rather than a word that refers to the function. If you store a word then you have to make sure the word is bound to an object which has a reference to that function, like this:
handlers: object [
foo-func: func [ a b ] [ print "foo" ]
bar-func: func [ a b ] [ print "bar" ]
]
handler-names: map [
"foo" foo-func
"bar" bar-func
]
apply get in handlers select handler-names name args
But if you just have a reference to the function in your map, you don't have to do the double indirect, and your code looks like this:
handlers: map reduce [
"foo" func [ a b ] [ print "foo" ]
"bar" func [ a b ] [ print "bar" ]
]
apply select handlers name args
Cleaner code, and more efficient too. Or if you're careful enough, like this:
handlers/(name) a b
The path method above will also work if you want the code to do nothing if there is no handler - common in cases where you have optional handlers, such as in GUIs.
You can even have more than one reference to the same function with different key names. You don't have to assign functions to words, they're just values. You can also use the path method to collect the handlers in the first place, saving a reduce
.
handlers: make map! 10 ; preallocate as many entries as you expect
handlers/("foo"): func [ a b ] [ print "foo" ]
handlers/("bar"): func [ a b ] [ print "bar" ]
handlers/("baz"): select handlers "bar" ; multiple references
That path syntax is just another way to call poke
, but some prefer it. We have to put the string values in parens because of a (hopefully temporary) syntax conflict, but within those parens the string keys work. It's a faster alternative to do select
or poke
.
foo-func in your map is just an unevaluated word
>> type? select handlers "foo"
== word!
You should first create your functions and then reduce the block, you use for creating your handler map so
handlers: make map! reduce [
"foo" :foo-func
"bar" :bar-func
]
then you have functions inside your map
>> type? select handlers "foo"
== function!
Try: .... f: do select handlers "foo" ....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With