[R] return value of {....}

Bert Gunter bgunter@4567 @end|ng |rom gm@||@com
Mon Jan 16 01:55:05 CET 2023


Well, weirdness is in the eyes of the beholder, I think.

In any case, R's scoping procedures are described in ?environment and
?assign and ?function, among other places; and in detail in the R
Language Definition. So no matter the behavior, as long as it is
clearly documented -- and consistent of course -- it's OK by me: it's
my job to learn it. Perhaps this just reflects my ignorance of what
might be considered "better" alternatives.

And of course, someone *did* write a compiler for R.

Cheers,
Bert

On Sun, Jan 15, 2023 at 3:39 PM Richard O'Keefe <raoknz using gmail.com> wrote:
>
> I wonder if the real confusino is not R's scope rules?
> (begin .) is not Lisp, it's Scheme (a major Lisp dialect),
> and in Scheme, (begin (define x ...) (define y ...) ...)
> declares variables x and y that are local to the (begin ...)
> form, just like Algol 68.  That's weirdness 1.  Javascript
> had a similar weirdness, when the ECMAscript process eventually
> addressed.  But the real weirdness in R is not just that the
> existence of variables is indifferent to the presence of curly
> braces, it's that it's *dynamic*.  In
> f <- function (...) {
>    ... use x ...
>    x <- ...
>    ... use x ...
> }
> the two occurrences of "use x" refer to DIFFERENT variables.
> The first occurrence refers to the x that exists outside the
> function.  It has to: the local variable does not exist yet.
> The assignment *creates* the variable, so the second
> occurrence of "use x" refers to the inner variable.
> Here's an actual example.
> > x <- 137
> > f <- function () {
> +     a <- x
> +     x <- 42
> +     b <- x
> +     list(a=a, b=b)
> + }
> > f()
> $a
> [1] 137
> $b
> [1] 42
>
> Many years ago I set out to write a compiler for R, and this was
> the issue that finally sank my attempt.  It's not whether the
> occurrence of "use x" is *lexically* before the creation of x.
> It's when the assignment is *executed* that makes the difference.
> Different paths of execution through a function may result in it
> arriving at its return point with different sets of local variables.
> R is the only language I routinely use that does this.
>
> So rule 1: whether an identifier in an R function refers to an
> outer variable or a local variable depends on whether an assignment
> creating that local variable has been executed yet.
> And rule 2: the scope of a local variable is the whole function.
>
> If the following transcript not only makes sense to you, but is
> exactly what you expect, congratulations, you understand local
> variables in R.
>
> > x <- 0
> > g <- function () {
> +     n <- 10
> +     r <- numeric(n)
> +     for (i in 1:n) {
> +         if (i == 6) x <- 100
> +         r[i] <- x + i
> +     }
> +     r
> + }
> > g()
>  [1]   1   2   3   4   5 106 107 108 109 110
>
>
> On Fri, 13 Jan 2023 at 23:28, Valentin Petzel <valentin using petzel.at> wrote:
>
> > Hello Akshay,
> >
> > R is quite inspired by LISP, where this is a common thing. It is not in
> > fact that {...} returned something, rather any expression evalulates to
> > some value, and for a compound statement that is the last evaluated
> > expression.
> >
> > {...} might be seen as similar to LISPs (begin ...).
> >
> > Now this is a very different thing compared to {...} in something like C,
> > even if it looks or behaves similarly. But in R {...} is in fact an
> > expression and thus has evaluate to some value. This also comes with some
> > nice benefits.
> >
> > You do not need to use {...} for anything that is a single statement. But
> > you can in each possible place use {...} to turn multiple statements into
> > one.
> >
> > Now think about a statement like this
> >
> > f <- function(n) {
> > x <- runif(n)
> > x**2
> > }
> >
> > Then we can do
> >
> > y <- f(10)
> >
> > Now, you suggested way would look like this:
> >
> > f <- function(n) {
> > x <- runif(n)
> > y <- x**2
> > }
> >
> > And we'd need to do something like:
> >
> > f(10)
> > y <- somehow_get_last_env_of_f$y
> >
> > So having a compound statement evaluate to a value clearly has a benefit.
> >
> > Best Regards,
> > Valentin
> >
> > 09.01.2023 18:05:58 akshay kulkarni <akshay_e4 using hotmail.com>:
> >
> > > Dear Valentin,
> > >                           But why should {....} "return" a value? It
> > could just as well evaluate all the expressions and store the resulting
> > objects in whatever environment the interpreter chooses, and then it would
> > be left to the user to manipulate any object he chooses. Don't you think
> > returning the last, or any value, is redundant? We are living in the
> > 21st century world, and the R-core team might,I suppose, have a definite
> > reason for"returning" the last value. Any comments?
> > >
> > > Thanking you,
> > > Yours sincerely,
> > > AKSHAY M KULKARNI
> > >
> > > ----------------------------------------
> > > *From:* Valentin Petzel <valentin using petzel.at>
> > > *Sent:* Monday, January 9, 2023 9:18 PM
> > > *To:* akshay kulkarni <akshay_e4 using hotmail.com>
> > > *Cc:* R help Mailing list <r-help using r-project.org>
> > > *Subject:* Re: [R] return value of {....}
> > >
> > > Hello Akshai,
> > >
> > > I think you are confusing {...} with local({...}). This one will
> > evaluate the expression in a separate environment, returning the last
> > expression.
> > >
> > > {...} simply evaluates multiple expressions as one and returns the
> > result of the last line, but it still evaluates each expression.
> > >
> > > Assignment returns the assigned value, so we can chain assignments like
> > this
> > >
> > > a <- 1 + (b <- 2)
> > >
> > > conveniently.
> > >
> > > So when is {...} useful? Well, anyplace where you want to execute
> > complex stuff in a function argument. E.g. you might do:
> > >
> > > data %>% group_by(x) %>% summarise(y = {if(x[1] > 10) sum(y) else
> > mean(y)})
> > >
> > > Regards,
> > > Valentin Petzel
> > >
> > > 09.01.2023 15:47:53 akshay kulkarni <akshay_e4 using hotmail.com>:
> > >
> > >> Dear members,
> > >>                              I have the following code:
> > >>
> > >>> TB <- {x <- 3;y <- 5}
> > >>> TB
> > >> [1] 5
> > >>
> > >> It is consistent with the documentation: For {, the result of the last
> > expression evaluated. This has the visibility of the last evaluation.
> > >>
> > >> But both x AND y are created, but the "return value" is y. How can this
> > be advantageous for solving practical problems? Specifically, consider the
> > following code:
> > >>
> > >> F <- function(X) {  expr; expr2; { expr5; expr7}; expr8;expr10}
> > >>
> > >> Both expr5 and expr7 are created, and are accessible by the code
> > outside of the nested braces right? But the "return value" of the nested
> > braces is expr7. So doesn't this mean that only expr7 should be accessible?
> > Please help me entangle this (of course the return value of F is expr10,
> > and all the other objects created by the preceding expressions are deleted.
> > But expr5 is not, after the control passes outside of the nested braces!)
> > >>
> > >> Thanking you,
> > >> Yours sincerely,
> > >> AKSHAY M KULKARNI
> > >>
> > >>     [[alternative HTML version deleted]]
> > >>
> > >> ______________________________________________
> > >> R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
> > >> https://stat.ethz.ch/mailman/listinfo/r-help
> > >> PLEASE do read the posting guide
> > http://www.R-project.org/posting-guide.html
> > >> and provide commented, minimal, self-contained, reproducible code.
> >
> >         [[alternative HTML version deleted]]
> >
> > ______________________________________________
> > R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
> > https://stat.ethz.ch/mailman/listinfo/r-help
> > PLEASE do read the posting guide
> > http://www.R-project.org/posting-guide.html
> > and provide commented, minimal, self-contained, reproducible code.
> >
>
>         [[alternative HTML version deleted]]
>
> ______________________________________________
> R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.



More information about the R-help mailing list