[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