I'm having trouble getting a while(TRUE)
loop to work. This example I think gets at the crux of the problem:
l <- list(x = 5)
while (TRUE){
with(l, if (x > 100) break else l$x <<- x + 5)
}
Which runs with error:
Error in
eval(expr, envir, enclos)
:no loop for break/next, jumping to top level
Strangely, the while
loop appears to have executed successfully:
l
# $x
# [1] 105
It appears the problem is I'm sending the break
statement in a sub-environment, since the following works as expected without error:
x = 5
while(TRUE){
if (x > 100) break else x <<- x+5
}
Thinking it's just an environments issue, I also tried replacing break
with eval(break, parent.env())
and eval(break, parent.frame())
, to no avail.
How can I stop this error?
I suppose sessionInfo()
may be relevant:
R version 3.2.4 (2016-03-10)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 14.04.3 LTS
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] readxl_0.1.0.9000 data.table_1.9.6 haven_0.2.0
loaded via a namespace (and not attached):
[1] rsconnect_0.4.1.11 tools_3.2.4 Rcpp_0.12.1 chron_2.3-47
A variant of @Vongo's suggestion is to capture the environment in which the evaluation is supposed to occur with environment()
, and then use evalq()
to have the break
evaluated in the right place.
l <- list(x = 5)
while (TRUE){
env <- environment()
with(l, if (x > 100) evalq(break, env) else l$x <<- x + 5)
}
This avoids parsing a text string and seems for that reason less hacky. Evaluating in the the captured environment env
allows the loop to be at any level in R code, not just in .GlobalEnv. This is like a non-local jump (aka GOTO) which makes it more difficult to reason about the code.
Maybe I don't understand all the stakes of the problem, but you could try :
l <- list(x = 5)
while (TRUE){
with(l, if (x > 100) eval(parse(text="break"), envir=.GlobalEnv) else l$x <<- x + 5)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With