Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[Function] with [Variable number of args]

 [1/11] from: gerardcote:sympatico:ca at: 5-Apr-2004 17:36


Hi List, while relaxing for a couple of days, I reread one of my old APL books and wanted to try implement some useful mechanisms for vector operations (a vector being a one dimensional array) using simple REBOL scripts. some of these mechanisms are somewhat similar to the higher-level functions Ladislav and other advanced REBOLers have written in the past. I'll give you 2 simple examples below since this is where I found some questions about the way REBOL can or not manage functions with a variable number of arguments. One of the mechanisms I wanted to emulate is simply an extension of the maths operators to take into account two arguments that are not only single values but that also could be a block of values, like in the use of my ++ function :
>>++ 1 2
== 3
>>++ 1 [1 2 3 4 5]
==[2 3 4 5 6]
>>++ [6 7 8 9 10] 1
==[7 8 9 10 11]
>>++ [1 2 3] [4 5 6]
==[5 7 9] All of this works well for now. The problem is that I also wanted to include in the same function another useful behaviour generally known as +/ in APL, like in this example :
>>++ [1 2 3 4] ; 1 + 2 + 3 + 4 == 10
==10 But I never was able to say REBOL to use only one argument - leaving the second one optional when necessary - and to not take into account of the second one defined like this : ++: function [arg1 arg2][ ... Can someone tell me if there is one simple way to do this with REBOL or if I have to define another independant function to do this. For now what I can do is check if the second arg is an empty block or none but this is not as elegant as it could be. I must admit that I didn't begin to look for an answer by myself yet but I will do this tonight. I found this could be interesting for other newbies too to know more about the subject. Thanks, Gerard

 [2/11] from: atruter::labyrinth::net::au at: 6-Apr-2004 8:43


Hi Gerard, Two ways of passing a variable number of arguments [that I know of] are blocks and refinements. Block usage: f: func [v [integer! block!]][...] f 1 f [1 2] or refinements: f: func [v1 [integer!] /var v2 [integer!]][...] f 1 f/var 1 2 It will be interesting to see what other techniques folks have! ;) Regards, Ashley

 [3/11] from: maximo:meteorstudios at: 5-Apr-2004 18:55


> Can someone tell me if there is one simple way to do this > with REBOL or if I have to define another independant > function to do this.
no. AFAIK rebol does not handle variable number of arguments, simply because it cannot know where a specific word should stop using values. rebol can only use a variable number of arguments if you use a refinement, to let it know that additional values are needed. each refinement specifiying how many additional tokens it will use up. if you implement your own dialect, then IT can decide if any given word should continue using the following values based on their type, for example. a simple dialect, could be built that simply uses one block and parses it, but still, you are supplying always One argument to the block parser itself. note that you can use a paren! like a block too... this can make it look more like a math expression... like: ++ (1 3) ++ (1) ++ (1 3 5 7) HTH! -MAx

 [4/11] from: gerardcote:sympatico:ca at: 5-Apr-2004 19:52


Hi Ashley and Maxim, From Ashley:
> Two ways of passing a variable number of arguments [that I know of] are > blocks and refinements. Block usage:
<<quoted lines omitted: 5>>
> f 1 > f/var 1 2
======================= From Maxim: ========= AFAIK rebol does not handle variable number of arguments, simply because it cannot know where a specific word should stop using values. rebol can only use a variable number of arguments if you use a refinement, to let it know that additional values are needed. each refinement specifiying how many additional tokens it will use up. ========================= Thanks for the information. I will try to figure how to do it the best I can with some combination of refinements and blocks I think. And then later - when time will permit - with my own dialect too, as Maxim suggested. If I am satisfied enough with the result, I'll also try to create some APL-like libray of simple Math functions to extend current REBOL calculations for use with 2 dimensional arrays "à la manière d'APL" but using Slim as the librarian so I can try to redefine the habitual arithmetics operators + - / * to include these extensions. I have already seen somebody here redefine the REBOL PRINT for use its own PRINT substitute with extensions instead and when leaving his own context put back the normal PRINT so everything seems normal after. Thanks again. Regards, Gerard

 [5/11] from: maximo:meteorstudios at: 5-Apr-2004 20:26


> I have already seen somebody here redefine the REBOL PRINT > for use its own PRINT substitute with extensions instead and > when leaving > his own context put back the normal PRINT so everything seems > normal after.
slim includes (as part of its basic toolset) a very advanced print mechanism, which allows you indent every part of the code you are using. vprint/vprobe also can be swicthed on and off run-time so that you can only see print statements when you need them, yet still leave them in the code for future debugging. because each slim uses its own context, you can switch the vprint on and off for each module separately and this allows you to debug ONLY the part of the code you are working on. I give a simple example of an indented output in the console, when verbose is set to on: pane/gl-layout(none : 108x110) ------------------------ ----- ROOT PANE ---- ------------------------ pane/gl-layout(none : 106x108) pane/gl-layout(none : 104x106) gl.text/gl-layout(Packages: 102x22) ] ] pane/gl-layout(none : 102x56) pane/gl-layout(none : 80x56) pane/gl-layout(none : 80x40) gl.text/gl-layout(: 80x20) ] ] gl.text/gl-layout(test-a.r: 80x20) ] ] ] ] gl.box/gl-layout(none: 80x16) ] ] in this example, the print statements in the functions themselves where silenced, but you still a clean diagram of program flow and can easily identify an error... all slim modules get the vprint system added at load time... so you don't have to fiddle around with any of this... its free and its completely hands off... you only have to use vprint instead of print and add the /in and /out refinement whenever you want to indent code (which is usually at the begining of a function or a loop, and at the end of these. also note that all modules cooexist as part of the indentation, so different modules using vprint, will all indent cleanly! also note that this system uses the global print, leaving you to do your own complimentary tricks... as usual... like saving to a log... yep... you get indented logs... sorry for this shameless plug ;-) -MAx

 [6/11] from: Christophe:Coussement:mil:be at: 6-Apr-2004 8:12


Hi Gerard, I once use this little trick for handling a variable number of argument: f: func [a [integer!] b [unset! integer!]][either value? 'b [a + b][a]]
>> f 1 2
== 3
>> f 1
== 1 Please remark that the type of the argument must be explicitely declared, otherwise: f: func [a b][either value? 'b [a + b][a]]
>> f 5 6
== 11
>> f 8
** Script Error: f is missing its b argument ** Near: f 8 Could this be useful to you ? gretz, ==christophe

 [7/11] from: cyphre:seznam:cz at: 6-Apr-2004 9:23


Hi Gerard, I'm using simmilar trick to Christophe's. example: f: func [ a [any-type!] b [any-type!] c [any-type!] d [any-type!] e [any-type!] ][ foreach v bind first :f 'a [ print [ v either unset? get/any v [ "not defined" ][ get v ] ] ] ]
>> f 1
a 1 b not defined c not defined d not defined e not defined
>> f 1 2 3
a 1 b 2 c 3 d not defined e not defined
>> f 1 2 3 4 5
a 1 b 2 c 3 d 4 e 5
>>
regards, Cyphre

 [8/11] from: robert:muench:robertmuench at: 6-Apr-2004 11:13


On Tue, 6 Apr 2004 08:12:01 +0200, Coussement Christophe <[Christophe--Coussement--mil--be]> wrote:
> I once use this little trick for handling a variable number of argument: > > f: func [a [integer!] b [unset! integer!]][either value? 'b [a + b][a]]
Hi, clever! This is a very cool trick... I hope I remember it. Robert

 [9/11] from: nitsch-lists:netcologne at: 6-Apr-2004 11:55


On Dienstag, 6. April 2004 11:13, Robert M. M=FCnch wrote:
> On Tue, 6 Apr 2004 08:12:01 +0200, Coussement Christophe > > <[Christophe--Coussement--mil--be]> wrote: > > I once use this little trick for handling a variable number of argument: > > > > f: func [a [integer!] b [unset! integer!]][either value? 'b [a + b][a]] > > Hi, clever! This is a very cool trick... I hope I remember it. Robert
Drawback is, [ f 1 print now ] is evaluated as [ (f 1 print) now ]. so you have to write [ (f 1) print now ]. Those unset! are most usefull for console, where you have implicit brackets. like [ help ] or [ help print ]. Gregg suggested in such a case to put arguments in block, which i prefer. !>>f: func[args][set[a b] reduce args ? a ? b ] !>>f [1] A is an integer of value: 1 B is a none of value: none !>>f[1 2] A is an integer of value: 1 B is an integer of value: 2 and can be made smarter for single arg: !>>f: func[a /local b][if block? a[set [a b] reduce a] ? a ? b] !>>f 1 A is an integer of value: 1 B is a none of value: none !>>f [1 2] A is an integer of value: 1 B is an integer of value: 2 Note the reduce, so you can write !>>f [1 + 2 3 + 4] A is an integer of value: 3 B is an integer of value: 7 -Volker

 [10/11] from: antonr:lexicon at: 7-Apr-2004 1:08


Of course, one has to be careful that the result of the expression following this "magical" function does not get eaten up by mistake. In this case, you should wrap in parens. Example (imagine in a script): (f 1) ; now let's do some real work ; lots of comments... probe my-var The value of my-var will not be passed as the second argument of f, because we remembered the parens. Aren't we lucky? Because of problems like these, I decided to avoid using optional arguments in general. I use it in one or two command-line functions, but these I never use in scripts. I think if you want to play the language game, go the parse way. Anton.

 [11/11] from: gerardcote:sympatico:ca at: 6-Apr-2004 19:48


Thanks to you all, Christophe, Cyphre, Volker, Anton and indirectly others too for your comments and vision about how to effectively use REBOL for solving the daily challenges we all have as "programmers" ... Your solutions will be studied diligently since they also showed me other interesting tracks to follow about concepts I plan to begin study soon (like the way to use bind and get for example - I just saw it in the OFFICIAL REBOL GUIDE but at the time I could not imagine how and when to use it for real). Maxim I will also begin to use Slim very soon to create my small APL inspired library. May for debugging too but in this case I will have to see (or create) some more examples of how and when to use each of its facilities. Regards, Gerard

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted