Reputation: 4298
Here's a test function I created to learn how lapply
and closures interact. My objective is to iterate over runif
function sequentially and print each iteration.
Mod_delay_by <- function(delay,f){
function(x,...){
Sys.sleep(delay)
cat(".")
#f(x,...)
cat("Processing",x,"\n",sep = "")
f(x,...)
}
}
Now let's use lapply
to call above function:
lapply(1:3,Mod_delay_by(0.1,runif))
When I call above function, I get the following sample output:
.Processing1
.Processing2
.Processing3
[[1]]
[1] 0.835246
[[2]]
[1] 0.1370997 0.4350032
[[3]]
[1] 0.1174749 0.4087628 0.7222604
I am surprised because all the three ".Processing" come before execution of runif
. Instead, I would have expected the output to be ...
.Processing1
[[1]]
[1] 0.835246
.Processing2
[[2]]
[1] 0.1370997 0.4350032
.Processing3
[[3]]
[1] 0.1174749 0.4087628 0.7222604
...because runif
(i.e. function f
) is immediately preceded by a call to ".Processing"
Can someone please explain why lapply
first finishes printing all the three Processing
, and then prints all three runifs
?
Thanks in advance for any help.
Upvotes: 0
Views: 485
Reputation: 42544
Apparently, the OP expects the output of f()
should be printed to the console window in each call like cat()
does.
Similar to what happens when the function is called directly from the console window:
> Mod_delay_by(0.1, runif)(2)
.Processing2
[1] 0.4519318 0.2331198
Please note that we won't see anything printed (except the output of cat()
) if the output is assigned to a variable:
> result <- Mod_delay_by(0.1, runif)(2)
.Processing2
So, if you call a function from the console window and the output is not assigned to a variable it is printed to the console window.
Now, f()
is being called from within the body of a function. This situation is different.
Instead of being printed to the console window, the output of f()
is returned to the caller. The help file ?"function"
says If the end of a function is reached without calling return
, the value of the last evaluated expression is returned.
This can be made more explicit by writing
return(f(x, ...))
So, only cat()
prints to console. The output of f()
is returned to the calling lapply()
function which collects all output in a list. Finally, this list is printed to the console only because it is not assigned to a variable.
If the output is assigned to a variable, we won't see anything printed except what cat()
prints to the console.
> result <- lapply(1:3, Mod_delay_by(0.1, runif))
.Processing1
.Processing2
.Processing3
To summarize, R is trying to save typing but the outcome depends on the context:
In the console window, f()
without assignment implies print(f())
.
In the body of a function, f()
as last evaluated expression implies return(f())
.
Upvotes: 1
Reputation: 3587
Function does not print anything to console by default.
.Processing1
.Processing2
.Processing3
[[1]]
[1] 0.835246
[[2]]
[1] 0.1370997 0.4350032
[[3]]
[1] 0.1174749 0.4087628 0.7222604
Here you are getting
.Processing1
.Processing2
.Processing3
because you are using cat
and rest are coming from the lapply
output.
If you change your defined function like this
Mod_delay_by <- function(delay,f){
function(x,...){
Sys.sleep(delay)
cat(".")
#f(x,...)
cat("Processing",x,"\n",sep = "")
print(f(x,...))
}
}
and then run
lapply(1:3,Mod_delay_by(0.1,runif))
you will get
#.Processing1
#[1] 0.5281055
#.Processing2
#[1] 0.892419 0.551435
#.Processing3
#[1] 0.4566147 0.9568333 0.4533342
#[[1]]
#[1] 0.5281055
#
#[[2]]
#[1] 0.892419 0.551435
#
#[[3]]
#[1] 0.4566147 0.9568333 0.4533342
Upvotes: 3