2016-03-23 7 views
6

Mam problem z uruchomieniem pętli while(TRUE). Ten przykład myślę trafia w sedno problemu:podczas przerwy w trybie TRUE + w środowisku podrzędnym

l <- list(x = 5) 

while (TRUE){ 
    with(l, if (x > 100) break else l$x <<- x + 5) 
} 

która biegnie z błędem:

Error in eval(expr, envir, enclos) :

no loop for break/next, jumping to top level

dziwne, pętla while wydaje się być wykonana pomyślnie:

l 
# $x 
# [1] 105 

To pojawia się problem: wysyłam oświadczenie break w pod-środowisku, ponieważ poniższe działa zgodnie z oczekiwaniami bez błędu:

x = 5 

while(TRUE){ 
    if (x > 100) break else x <<- x+5 
} 

Myśląc, że to tylko kwestia środowiska, próbowałem również zastąpienie break z eval(break, parent.env()) i eval(break, parent.frame()), bezskutecznie.

Jak mogę zatrzymać ten błąd?


Przypuszczam sessionInfo() mogą być istotne:

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  
+0

Czy jest jakiś powód używania 'with'? Dlaczego nie tylko "jeśli (l $ x> 100) złamie jeszcze l $ x <-l $ x + 100"? – nicola

+0

@nicola kontekst problemu jest nieco inny; Wybrałem to, aby powielić to, co uważam za niezbędne. To powiedziawszy, w moim faktycznym użyciu, 'break' jest wysyłany w ramach wywołania' [.data.table' – MichaelChirico

+0

Może lepiej wyjaśnienie kontekstu byłoby pomocne, ponieważ tutaj jest czysto problem środowiska: 'while (TRUE) with() l, break) 'powoduje ten sam błąd. Najwyraźniej 'with' tworzy środowisko, z którego R nie oczekuje" zerwania ". – nicola

Odpowiedz

3

wariant @ Propozycja Vongo polega na przechwytywaniu środowiska, w którym ma nastąpić ewaluacja, z environment(), a następnie użyj evalq(), aby uzyskać break ocenione we właściwym miejscu.

l <- list(x = 5) 
while (TRUE){ 
    env <- environment() 
    with(l, if (x > 100) evalq(break, env) else l$x <<- x + 5) 
} 

Dzięki temu unika się parsowania łańcucha tekstowego i wydaje się z tego powodu mniej hackowy. Ocena w przechwyconym środowisku pozwala na uzyskanie pętli na dowolnym poziomie w kodzie R, a nie tylko w .GlobalEnv. Jest to podobne do nielokalnego skoku (inaczej GOTO), co utrudnia rozumowanie kodu.

+0

również 'evalq (break, parent.env (environment()))'. Nadal nie jestem pewien, dlaczego oryginalny kod nie był nieskończoną pętlą, jeśli 'break' został wysłany do niewłaściwego środowiska. Jakiegokolwiek powodu? – MichaelChirico

+0

@MichaelChirico lepiej być wyraźnym o env = zamiast polegać na kolejności stosu wywołań do odkrycia, ponieważ programista może przypadkowo zmienić stos wywołań.Oryginalny kod wygenerował błąd, a na skutek błędu pętla się zakończyła. –

+0

O, to ma sens. – MichaelChirico

1

Może nie rozumiem wszystkie udziały problemu, ale można spróbować:

l <- list(x = 5) 
while (TRUE){ 
    with(l, if (x > 100) eval(parse(text="break"), envir=.GlobalEnv) else l$x <<- x + 5) 
} 
+0

Przepraszamy, po prostu wracamy . Myślę, że @Martin Morgan wyjaśnił to podejście, a nawet je poprawił. Kudos! – Vongo

Powiązane problemy