I have an arbitrary function with multiple arguments, and I want to call it from command-line like this:
program myfun 7 24 15
I tried to do it this way:
myfun Func: [A B C][...]
ARGS: Probe System/Options/Args
Print Do [ARGS/1 Remove ARGS]
My way of thinking is that I retrieve command name with ARGS/1, then remove it from argument list, enclose in a block with the rest of arguments and evaluate with Do. However, it just returns arguments without the function name: 7 24 15
. I also tried to copy both values to different variables, but no luck, and I cannot understand what is wrong.
The main issue is that the last line does not do what you think it should:
Do [ARGS/1 Remove ARGS]
will return:
["7" "24" "15"]
instead of calling myfun
function with those arguments. That happens because do [args/1]
is not equivalent to do args/1
:
>> args: ["myfun" "7" "24" "15"]
== ["myfun" "7" "24" "15"]
>> Do [ARGS/1]
== "myfun"
>> Do ARGS/1
*** Script Error: myfun has no value
*** Where: Do
*** Near : myfun
*** Stack:
As you can see, in the first case, do
is evaluating a block and returning the last value, so Args/1
is evaluated to "myfun"
and returned by do
. In the second case, Args/1
is evaluated to "myfun"
, then "myfun"
is passed as argument to do
, resulting in do
loading that value and evaluating it (resulting in an error in my case, as I did not define that word).
However, it just returns arguments without the function name: 7 24 15
Using print
implies an extra level of evaluation (as print
reduces its block of arguments), so you can easily get fooled by the reduced output. If you use probe
instead (recommended for debugging), you would get ["7" "24" "15"]
.
Now to achieve what you want, you can either do it yourself, step by step or use an existing library.
Here is an example code:
Red [File: %program.red]
to-int: :to-integer
myfun: func [a b c][(to-int a) + (to-int b) + (to-int c)]
args: system/options/args
print apply to-word args/1 next args
This approach relies on apply
which will call a function (passed as word or function value) with a list of arguments (passed as a block of values). So:
to-word args/1
fetches and converts the function's name to the right type.next args
creates the list of arguments by skipping the function's name at first position in the block (no needs to remove it, just skipping is simpler).The CLI library is doing what you need (and a lot more). Feel free to join us in our Chat room if you're not there already and ask @hiiamboris if you need any info about his CLI library.
Hope this helps.