Closed arashHaratian closed 3 years ago
Hey @arashHaratian, thank you for raising this issue.
It is my understanding, that functions capture their environments at creation time ("closure"). From the logic of the computation one could say that f3 is contained in f2 and f2 is contained in f1 and I think this is expressed in the "binding scheme". I did just try to clarify the explanation in https://github.com/Tazinho/Advanced-R-Solutions/commit/c28a859d8d51ba72e63404736a327c41f3de3838.
I based the diagram on the first diagram on https://adv-r.hadley.nz/environments.html#function-environments where f binds the global environment in a similar way.
@hadley could you check this exercise (https://advanced-r-solutions.rbind.io/environments.html#special-environments, Q2) once again?
thanks for your response to this issue.
my problem is that f2
is not an argument for the f1()
. (if your scheme follows the conventions of the original book)
so, I think the diagram is something like this:
(sorry for the awful photo 😅)
I see your point: x1
is an argument to f1
, while f2
is part of the functions body (which is not drawn in Adv R). In the diagram both look the same. Also the value for x1
is not captured when the function is created, but passed at execution time.
For this exercise it's probably necessary to draw the function body's content and I would argue that both function body and function arguments are ultimately part of the same environment.
Thank you so much for the helpful graphic 😍. I believe in this are too many environments as seen by the number of dots (I believe it should be the global environment and 3 function environments in total) and also the values of x1
, x2
, x3
are not represented (which could be easily added, I guess).
yes, I did not add x1
, x2
, and x3
values and bindings.
my point is f2()
function binds to the variable name f2
inside the execution env of the f1()
, f3()
function binds to the variable name f3
inside the execution env of the f2()
.
check the plus
example in the book. this question is similar to that.
Hey @arashHaratian,
I just had another look at the exercise and also the plus
-example in the Execution Environments-Subsubchapter.
I still believe the diagram currently presented is correct:
plus_one
example we do not assign f1
, f2
, f2
to an object as we do in plus_one <- plus(1)
. I think, that is why the execution environment doesn't need to be captured.f1 <- function(x1) {
f2 <- function(x2) {
f3 <- function(x3) {
x1 + x2 + x3
print(rlang::env_print())
}
f3(3)
print(rlang::env_print())
}
f2(2)
print(rlang::env_print())
}
f1(1)
#> <environment: 0x5589c1864c60>
#> parent: <environment: 0x5589c1864e20>
#> bindings:
#> * x3: <dbl>
#> <environment: 0x5589c1864e20>
#> parent: <environment: 0x5589c1864fe0>
#> bindings:
#> * f3: <fn>
#> * x2: <dbl>
#> <environment: 0x5589c1864fe0>
#> parent: <environment: global>
#> bindings:
#> * f2: <fn>
#> * x1: <dbl>
What do you think? :)
yes, I had done this experimentation and I found the same result, but these environments are the execution environments.
this is the example of the book ( above the plus_one
example )
h2 <- function(x) {
a <- x * 2
rlang::current_env()
}
e <- h2(x = 10)
rlang::env_print(e)
print(e)
and so the bindings that are printed are in those environments ( like a
in the above example).
am I right?
I'm already quite sure you are correct. Now, we just have to wait until I get it too. 😂
I agree with the execution environments...
I'll take another look shortly, thank you for your patience. :D
So, I've updated the text again.
I also made a sketch of how the diagram could look if we include the distinction between function environments at creation time and execution time.
@arashHaratian please let me know what you think of it now. :)
I think it's great and it's more complete than what I drew. 👌👌
That's good to hear! :)
(The only thing that still confuses me a little, is that the rlang::env_print()
outputs only seem to show the execution environments and that these have each other as parent environments. In the diagram each execution environment seems to bind to it's function environment - do you understand what I mean?)
I think the answer is they bind to the environment that function binds to. (a quote from the book: "the parent of the execution environment is the function environment."
the book uses this convention to make the graph easier, instead of drawing the arrow from the execution environment to the function environment.
so, in fact, you can draw the arrow from the execution env of the f1
to the global_env
.
I hope I answered your question correctly.
I think the diagram in answer to the question 7.4.5.2 should shows the execution environments of functions. so
f2
name must be in execution environment of functionf1()
and bindsf2()
,f3
name must be in execution environment of functionf2()
and bindsf3()
. Is that right?