Guten tag Rony,
What is a "closure" and what is your syntax for it?
>
A closure is a block (class RexxBlock) who remembers the value of the
variables defined in its outer environment.
The syntax is {::closure ...}, where ::closure is a tag which can be
abbreviated ::cl.
For a list of all tags, see
http://oorexx.svn.sourceforge.net/viewvc/oorexx/sandbox/jlf/trunk/interpreter/RexxClasses/Parser.orx?view=log
> E.g. what does "{}~variables" do and why is "[::closure}~variables"
> different to the former?
>
{} is an empty source literal. The default tag is ::routine.
{::closure} is a source literal tagged ::closure. The tag makes the
difference.
Since doing a copy of .context~variables has a cost, there is no reason to
do it when not needed.
Not sure I will keep the method ~variables on RexxBlock. Currently, I need
it to initialize the closure instance, but there is probably no reason for
an end-user to have access to this directory.
Ex1 :
> In this example, you create functions on-the-fly from a common block.
>
> range = { use arg min, max ; return { ::closure expose min max ; use arg
> num ; return min <= num & num <= max }}
>
> Hmm, why would you have nested blocks?
>
The first block can be rewritten as a routine, no more nested blocks, but
the code is less compact, and the order less natural (you discover the
definition of the routine after the place from where it's called). The
inner block is an object (RexxBlock) returned by the routine.
from5to8 = range(5, 8) -- function call, here no tilde
say from5to8~(6) -- from5to8 is a RexxBlock to which the message "~()" is
sent
::routine range
use arg min, max
return { ::closure expose min max ; use arg num ; return min <= num & num
<= max }
Why is the inner block led in by "::closure" and why is that necessary in
> this example?
>
The tag ::closure is needed to capture the values of min and max.
When the RexxBlock is returned to the caller, the values of min and max are
still available, despite the fact the context of the routine 'range' no
longer exists.
> What does "expose" in a closure do?
>
A closure is an instance of .Closure which has only one "do" method, whose
source is given by the source literal (after removing the tag). The
directory of variables on the RexxBlock is used to create instance
variables inside the closure instance. The "expose" is used to make visible
the needed variables.
This is a naive implementation, there is room for optimization.
> What does "use arg num" in the inner block refer to and why?
>
Since the object returned by "range" is a RexxBlock, you can execute this
block and pass arguments. Here, the block expects a number argument.
> So is "from5to8" an object representing the code above and by sending
> that doer/executable/runnable object a message, it gets executed supplying
> the arguments of the message to that code block?
>
yes, exactly.
from5to8 is a RexxBlock to which the message "~()" is sent with the
argument 6. This message is forwarded as "do" message to the doer
associated to the RexxBlock. Here, the doer is a closure. The "do" method
receives the argument 6 and has access to the exposed min and max
variables, which were captured when the "range" routine was called.
from20to30 = range~(20, 30)
>
> Again, is "from20to30" a block of executable code, where "min" and "max"
> are set and which later can be used to execute code?
>
yes.
Each time the "range" routine is called, a new instance of RexxBlock is
returned, which holds the .context~variables of the "range" routine. Since
the parameters min and max belongs to this directory, they are captured.
And if so, why is the argument to the message not supplied as an argument
> to the executable code (outer block), but obviously as an argument to the
> inner block defined to be a closure?
>
See comments above.
> Ex2 :
> In this example, a closure is needed to have access to the 'translation'
> variable. You can't pass it by parameter, because it's not you who calls
> the block.
>
> Who does call/execute the block then?
>
The block is called by the mapW method.
You call the mapW method, but you have no way to pass the translation
directory to it, because mapW accepts only one parameter : the action to
apply on each word of the string.
The action must be a doer factory, i.e. must understand ~doer. The action
can be a routine or a method or a message or a coactivity or a closure or a
block. Among all those objects, only a block is really a factory. The other
objects return themselves when sending the message ~doer, because they are
already executable.
> translation = .Directory~new
> translation["quick"] = "slow"
> translation["lazy"] = "nervous"
> translation["brown"] = "yellow"
> translation["dog"] = "cat"
> translation~setMethod("UNKNOWN", "return arg(1)")
> say "The quick brown fox jumps over the lazy dog"~mapW{::cl expose
> translation ; translation[arg(1)]}
>
> Which argument does "arg(1)" refer to in the above statement?
>
arg(1) is the current word being processed.
What does the method "mapW" do? What are the arguments to it? What would
> be the input and what would be the produced output?
>
The mapW method iterates over the words of a string and execute the action
passed as parameter. This is called a "higher-order function" in functional
languages.
If the action understands "functionDoer" (currently only a block
understands this message) then the source is transformed to insert "use arg
value, index". The value is the current word, the index is the word number.
Otherwise only the current word is passed as parameter.
I don't elaborate on the transformation of source, but this is something
useful when working interactively from ooRexxShell, where you want to enter
concise expressions.
For examples of higher-order functions, see
http://oorexx.svn.sourceforge.net/viewvc/oorexx/sandbox/jlf/samples/extension/functional-test.output.txt?view=log
Ex3 :
> In this example, the 'partial' method returns a closure which remember the
> parameter 10.
>
> Where is the method "partial" defined and what does it do?
>
Defined here :
http://oorexx.svn.sourceforge.net/viewvc/oorexx/sandbox/jlf/samples/extension/doers.cls?view=log
The method "partial" lets provide some arguments in advance, and returns a
closure which remembers these arguments. When you do the final call, you
have just to provide the remaining arguments.
> What executable code object does it return?
>
a closure.
> add10 = "+"~partial(10)
>
> What does "add10" represent in this case?
>
Try this in oorexxshell :
add10 = "+"~partial(10)
add10=
add10~instanceMethod("do")~source=
You will see that the source starts with
expose self args1
args2 = arg(1, "a")
self is the doer to which the "partial" message has been sent (here "+").
args1 is the array of arguments passed to "partial".
args2 is the array of remaining arguments that will be passed to the
closure.
>From args1 and args2, a complete array of arguments is built (args)
and the source ends with :
forward message "do" arguments (args) to (self)
> say add10~(1) -- 11
>
> Why would one get "11" as a result in this case?
>
The last instruction of the closure is :
forward message "do" arguments (.array~of(10,1)) to ("+")
"+" is a string, and when used as a doer, a string is a message.
The first argument becomes the self, so we do :
10~"+"(1) -- 11
Another example of a message used as a doer :
say "length"~("John") -- 4 ("John"~"length")
As said previously, the goal of the doers is to provide a common
abstraction for routine, method, message, coactivity, closure, block.
When an action is passed as parameter to higher-order functions like
~reduce, ~map, the protocol is always the same :
doer = action~doer
doer~do(arg1, arg2, ...)
Each doer has its own "do" method, and knows what to do with the arguments.
routine : forward message "call"
method : use strict arg object, ... ; forward to (object) message "run"
array (self, "a", arg(2,"a"))
message : use strict arg object, ... ; forward to (object) message
("sendWith") array (self, arg(2,"a"))
coactivity : forward message ("resume")
closure : user-defined source literal
block : forward to (self~doer)
Jean-Louis
------------------------------------------------------------------------------
Ridiculously easy VDI. With Citrix VDI-in-a-Box, you don't need a complex
infrastructure or vast IT resources to deliver seamless, secure access to
virtual desktops. With this all-in-one solution, easily deploy virtual
desktops for less than the cost of PCs and save 60% on VDI infrastructure
costs. Try it free! http://p.sf.net/sfu/Citrix-VDIinabox
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel