[R] Evaluating lazily 'f<-' ?

Leonard Mada |eo@m@d@ @end|ng |rom @yon|c@eu
Wed Sep 15 08:26:31 CEST 2021


Hello Andrew,


On 9/15/2021 6:53 AM, Andrew Simmons wrote:
> names(x) <- c("some names")
>
> if different from
>
> `names<-`(x, value = c("some names"))
>
> because the second piece of code does not ever call `<-`. The first 
> piece of code is (approximately) equivalent to
>
> `*tmp*` <- x
> `*tmp*` <- `names<-`(`*tmp*`, value = c("some names"))
> x <- `*tmp*`


This is my question:

Would there be any negative impact if the code is changed to:

x <- 'names<-'(x, value=...);

The "x" will be evaluated inside 'names<-' and this function outputs & 
assigns "x". The "creation" of "x" in the current environment is done 
only after the call to 'names<-' (if it did not exist before).


Leonard


>
> Another example,
>
> y <- `names<-`(x, value = c("some names"))
>
> now y will be equivalent to x if we did
>
> names(x) <- c("some names")
>
> except that the first will not update x, it will still have its old names.
>
> On Mon, Sep 13, 2021 at 4:33 PM Leonard Mada <leo.mada using syonic.eu 
> <mailto:leo.mada using syonic.eu>> wrote:
>
>
>     On 9/13/2021 11:28 PM, Andrew Simmons wrote:
>>     In the example you gave : r(x) <- 1
>>     r(x) is never evaluated, the above calls `r<-`,
>>     in fact r does not even have to be an existing function.
>
>
>     I meant:
>
>     '*tmp*' <- x; # "x" is evaluated here;
>
>     'r<-' is called after this step, which makes sense in the case of
>     subsetting;
>
>
>     But I am wondering if changing this behaviour, when NO subsetting
>     is performed, would have any impact.
>
>     e.g. names(x) = c("some names");
>
>     # would it have any impact to skip the evaluation of "x" and call
>     directly:
>
>     'names<-'(x, value);
>
>
>     Leonard
>
>
>>
>>     On Mon, Sep 13, 2021, 16:18 Leonard Mada <leo.mada using syonic.eu
>>     <mailto:leo.mada using syonic.eu>> wrote:
>>
>>         Hello,
>>
>>
>>         I have found the evaluation: it is described in the section
>>         on subsetting. The forced evaluation makes sense for subsetting.
>>
>>
>>         On 9/13/2021 9:42 PM, Leonard Mada wrote:
>>>
>>>         Hello Andrew,
>>>
>>>
>>>         I try now to understand the evaluation of the expression:
>>>
>>>         e = expression(r(x) <- 1)
>>>
>>>         # parameter named "value" seems to be required;
>>>         'r<-' = function(x, value) {print("R");}
>>>         eval(e, list(x=2))
>>>         # [1] "R"
>>>
>>>         # both versions work
>>>         'r<-' = function(value, x) {print("R");}
>>>         eval(e, list(x=2))
>>>         # [1] "R"
>>>
>>>
>>>         ### the Expression
>>>         e[[1]][[1]] # "<-", not "r<-"
>>>         e[[1]][[2]] # "r(x)"
>>>
>>>
>>>         The evaluation of "e" somehow calls "r<-", but evaluates
>>>         also the argument of r(...). I am still investigating what
>>>         is actually happening.
>>>
>>
>>         The forced evaluation is relevant for subsetting, e.g.:
>>         expression(r(x)[3] <- 1)
>>         expression(r(x)[3] <- 1)[[1]][[2]]
>>         # r(x)[3] # the evaluation details are NOT visible in the
>>         expression per se;
>>         # Note: indeed, it makes sens to first evaluate r(x) and then
>>         to perform the subsetting;
>>
>>
>>         However, in the case of a non-subsetted expression:
>>         r(x) <- 1;
>>         It would make sense to evaluate lazily r(x) if no subsetting
>>         is involved (more precisely "r<-"(x, value) ).
>>
>>         Would this have any impact on the current code?
>>
>>
>>         Sincerely,
>>
>>
>>         Leonard
>>
>>
>>>
>>>         Sincerely,
>>>
>>>
>>>         Leonard
>>>
>>>
>>>         On 9/13/2021 9:15 PM, Andrew Simmons wrote:
>>>>         R's parser doesn't work the way you're expecting it to.
>>>>         When doing an assignment like:
>>>>
>>>>
>>>>         padding(right(df)) <- 1
>>>>
>>>>
>>>>         it is broken into small stages. The guide "R Language
>>>>         Definition" claims that the above would be equivalent to:
>>>>
>>>>
>>>>         `<-`(df, `padding<-`(df, value = `right<-`(padding(df),
>>>>         value = 1)))
>>>>
>>>>
>>>>         but that is not correct, and you can tell by using
>>>>         `substitute` as you were above. There isn't a way to do
>>>>         what you want with the syntax you provided, you'll have to
>>>>         do something different. You could add a `which` argument to
>>>>         each style function, and maybe put the code for `match.arg`
>>>>         in a separate function:
>>>>
>>>>
>>>>         match.which <- function (which)
>>>>         match.arg(which, c("bottom", "left", "top", "right"),
>>>>         several.ok = TRUE)
>>>>
>>>>
>>>>         padding <- function (x, which)
>>>>         {
>>>>             which <- match.which(which)
>>>>             # more code
>>>>         }
>>>>
>>>>
>>>>         border <- function (x, which)
>>>>         {
>>>>             which <- match.which(which)
>>>>             # more code
>>>>         }
>>>>
>>>>
>>>>         some_other_style <- function (x, which)
>>>>         {
>>>>             which <- match.which(which)
>>>>             # more code
>>>>         }
>>>>
>>>>
>>>>         I hope this helps.
>>>>
>>>>         On Mon, Sep 13, 2021 at 12:17 PM Leonard Mada
>>>>         <leo.mada using syonic.eu <mailto:leo.mada using syonic.eu>> wrote:
>>>>
>>>>             Hello Andrew,
>>>>
>>>>
>>>>             this could work. I will think about it.
>>>>
>>>>
>>>>             But I was thinking more generically. Suppose we have a
>>>>             series of functions:
>>>>             padding(), border(), some_other_style();
>>>>             Each of these functions has the parameter "right" (or
>>>>             the group of parameters c("right", ...)).
>>>>
>>>>
>>>>             Then I could design a function right(FUN) that assigns
>>>>             the value to this parameter and evaluates the function
>>>>             FUN().
>>>>
>>>>
>>>>             There are a few ways to do this:
>>>>
>>>>             1.) Other parameters as ...
>>>>             right(FUN, value, ...) = value; and then pass "..." to FUN.
>>>>             right(value, FUN, ...) = value; # or is this the
>>>>             syntax? (TODO: explore)
>>>>
>>>>             2.) Another way:
>>>>             right(FUN(...other parameters already specified...)) =
>>>>             value;
>>>>             I wanted to explore this 2nd option: but avoid
>>>>             evaluating FUN, unless the parameter "right" is
>>>>             injected into the call.
>>>>
>>>>             3.) Option 3:
>>>>             The option you mentioned.
>>>>
>>>>
>>>>             Independent of the method: there are still
>>>>             weird/unexplained behaviours when I try the initial
>>>>             code (see the latest mail with the improved code).
>>>>
>>>>
>>>>             Sincerely,
>>>>
>>>>
>>>>             Leonard
>>>>
>>>>
>>>>             On 9/13/2021 6:45 PM, Andrew Simmons wrote:
>>>>>             I think you're trying to do something like:
>>>>>
>>>>>             `padding<-` <- function (x, which, value)
>>>>>             {
>>>>>                 which <- match.arg(which, c("bottom", "left",
>>>>>             "top", "right"), several.ok = TRUE)
>>>>>                 # code to pad to each side here
>>>>>             }
>>>>>
>>>>>             Then you could use it like
>>>>>
>>>>>             df <- data.frame(x=1:5, y = sample(1:5, 5))
>>>>>             padding(df, "right") <- 1
>>>>>
>>>>>             Does that work as expected for you?
>>>>>
>>>>>             On Mon, Sep 13, 2021, 11:28 Leonard Mada via R-help
>>>>>             <r-help using r-project.org <mailto:r-help using r-project.org>>
>>>>>             wrote:
>>>>>
>>>>>                 I try to clarify the code:
>>>>>
>>>>>
>>>>>                 ###
>>>>>                 right = function(x, val) {print("Right");};
>>>>>                 padding = function(x, right, left, top, bottom)
>>>>>                 {print("Padding");};
>>>>>                 'padding<-' = function(x, ...) {print("Padding = ");};
>>>>>                 df = data.frame(x=1:5, y = sample(1:5, 5)); # anything
>>>>>
>>>>>                 ### Does NOT work as expected
>>>>>                 'right<-' = function(x, value) {
>>>>>                      print("This line should be the first printed!")
>>>>>                      print("But ERROR: x was already evaluated,
>>>>>                 which printed \"Padding\"");
>>>>>                      x = substitute(x); # x was already evaluated
>>>>>                 before substitute();
>>>>>                      return("Nothing"); # do not now what the
>>>>>                 behaviour should be?
>>>>>                 }
>>>>>
>>>>>                 right(padding(df)) = 1;
>>>>>
>>>>>                 ### Output:
>>>>>
>>>>>                 [1] "Padding"
>>>>>                 [1] "This line should be the first printed!"
>>>>>                 [1] "But ERROR: x was already evaluated, which
>>>>>                 printed \"Padding\""
>>>>>                 [1] "Padding = " # How did this happen ???
>>>>>
>>>>>
>>>>>                 ### Problems:
>>>>>
>>>>>                 1.) substitute(x): did not capture the expression;
>>>>>                 - the first parameter of 'right<-' was already
>>>>>                 evaluated, which is not
>>>>>                 the case with '%f%';
>>>>>                 Can I avoid evaluating this parameter?
>>>>>                 How can I avoid to evaluate it and capture the
>>>>>                 expression: "right(...)"?
>>>>>
>>>>>
>>>>>                 2.) Unexpected
>>>>>                 'padding<-' was also called!
>>>>>                 I did not know this. Is it feature or bug?
>>>>>                 R 4.0.4
>>>>>
>>>>>
>>>>>                 Sincerely,
>>>>>
>>>>>
>>>>>                 Leonard
>>>>>
>>>>>
>>>>>                 On 9/13/2021 4:45 PM, Duncan Murdoch wrote:
>>>>>                 > On 13/09/2021 9:38 a.m., Leonard Mada wrote:
>>>>>                 >> Hello,
>>>>>                 >>
>>>>>                 >>
>>>>>                 >> I can include code for "padding<-"as well, but
>>>>>                 the error is before that,
>>>>>                 >> namely in 'right<-':
>>>>>                 >>
>>>>>                 >> right = function(x, val) {print("Right");};
>>>>>                 >> # more options:
>>>>>                 >> padding = function(x, right, left, top, bottom)
>>>>>                 {print("Padding");};
>>>>>                 >> 'padding<-' = function(x, ...) {print("Padding
>>>>>                 = ");};
>>>>>                 >> df = data.frame(x=1:5, y = sample(1:5, 5));
>>>>>                 >>
>>>>>                 >>
>>>>>                 >> ### Does NOT work
>>>>>                 >> 'right<-' = function(x, val) {
>>>>>                 >>         print("Already evaluated and also does
>>>>>                 not use 'val'");
>>>>>                 >>         x = substitute(x); # x was evaluated before
>>>>>                 >> }
>>>>>                 >>
>>>>>                 >> right(padding(df)) = 1;
>>>>>                 >
>>>>>                 > It "works" (i.e. doesn't generate an error) for
>>>>>                 me, when I correct
>>>>>                 > your typo:  the second argument to `right<-`
>>>>>                 should be `value`, not
>>>>>                 > `val`.
>>>>>                 >
>>>>>                 > I'm still not clear whether it does what you
>>>>>                 want with that fix,
>>>>>                 > because I don't really understand what you want.
>>>>>                 >
>>>>>                 > Duncan Murdoch
>>>>>                 >
>>>>>                 >>
>>>>>                 >>
>>>>>                 >> I want to capture the assignment event inside
>>>>>                 "right<-" and then call
>>>>>                 >> the function padding() properly.
>>>>>                 >>
>>>>>                 >> I haven't thought yet if I should use:
>>>>>                 >>
>>>>>                 >> padding(x, right, left, ... other parameters);
>>>>>                 >>
>>>>>                 >> or
>>>>>                 >>
>>>>>                 >> padding(x, parameter) <- value;
>>>>>                 >>
>>>>>                 >>
>>>>>                 >> It also depends if I can properly capture the
>>>>>                 unevaluated expression
>>>>>                 >> inside "right<-":
>>>>>                 >>
>>>>>                 >> 'right<-' = function(x, val) {
>>>>>                 >>
>>>>>                 >> # x is automatically evaluated when using 'f<-'!
>>>>>                 >>
>>>>>                 >> # but not when implementing as '%f%' =
>>>>>                 function(x, y);
>>>>>                 >>
>>>>>                 >> }
>>>>>                 >>
>>>>>                 >>
>>>>>                 >> Many thanks,
>>>>>                 >>
>>>>>                 >>
>>>>>                 >> Leonard
>>>>>                 >>
>>>>>                 >>
>>>>>                 >> On 9/13/2021 4:11 PM, Duncan Murdoch wrote:
>>>>>                 >>> On 12/09/2021 10:33 a.m., Leonard Mada via
>>>>>                 R-help wrote:
>>>>>                 >>>> How can I avoid evaluation?
>>>>>                 >>>>
>>>>>                 >>>> right = function(x, val) {print("Right");};
>>>>>                 >>>> padding = function(x) {print("Padding");};
>>>>>                 >>>> df = data.frame(x=1:5, y = sample(1:5, 5));
>>>>>                 >>>>
>>>>>                 >>>> ### OK
>>>>>                 >>>> '%=%' = function(x, val) {
>>>>>                 >>>>        x = substitute(x);
>>>>>                 >>>> }
>>>>>                 >>>> right(padding(df)) %=% 1; # but ugly
>>>>>                 >>>>
>>>>>                 >>>> ### Does NOT work
>>>>>                 >>>> 'right<-' = function(x, val) {
>>>>>                 >>>> print("Already evaluated and also does not
>>>>>                 use 'val'");
>>>>>                 >>>>        x = substitute(x); # is evaluated before
>>>>>                 >>>> }
>>>>>                 >>>>
>>>>>                 >>>> right(padding(df)) = 1
>>>>>                 >>>
>>>>>                 >>> That doesn't make sense.  You don't have a
>>>>>                 `padding<-` function, and
>>>>>                 >>> yet you are trying to call right<- to assign
>>>>>                 something to padding(df).
>>>>>                 >>>
>>>>>                 >>> I'm not sure about your real intention, but
>>>>>                 assignment functions by
>>>>>                 >>> their nature need to evaluate the thing they
>>>>>                 are assigning to, since
>>>>>                 >>> they are designed to modify objects, not
>>>>>                 create new ones.
>>>>>                 >>>
>>>>>                 >>> To create a new object, just use regular
>>>>>                 assignment.
>>>>>                 >>>
>>>>>                 >>> Duncan Murdoch
>>>>>                 >
>>>>>
>>>>>                 ______________________________________________
>>>>>                 R-help using r-project.org <mailto:R-help using r-project.org>
>>>>>                 mailing list -- To UNSUBSCRIBE and more, see
>>>>>                 https://stat.ethz.ch/mailman/listinfo/r-help
>>>>>                 <https://stat.ethz.ch/mailman/listinfo/r-help>
>>>>>                 PLEASE do read the posting guide
>>>>>                 http://www.R-project.org/posting-guide.html
>>>>>                 <http://www.R-project.org/posting-guide.html>
>>>>>                 and provide commented, minimal, self-contained,
>>>>>                 reproducible code.
>>>>>

	[[alternative HTML version deleted]]



More information about the R-help mailing list