2016-03-23 32 views
6

Çalışmak için while(TRUE) döngüsünü almada sorun yaşıyorum.Alt ortamda TRUE + kopma

l <- list(x = 5) 

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

hata ile çalışır: Bence Bu örnek problemin kilit noktalarında alır Garip

Error in eval(expr, envir, enclos) :

no loop for break/next, jumping to top level

, while döngü başarıyla yürütüldü gibi görünüyor:

l 
# $x 
# [1] 105 

O Sorun şu ki, bir alt ortamda break ifadesini gönderiyor, çünkü aşağıdakiler hatasız olarak çalışıyor:

x = 5 

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

bu sadece bir ortamları konu düşünme, ben de boşuna, eval(break, parent.env()) ve eval(break, parent.frame()) ile break yerine çalıştı.

Bu hatayı nasıl durdurabilirim? Belki

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

'with' kullanmak için bir neden var mı? Neden sadece '' (l $ x> 100) 'i bozarsa l $ x <-l $ x + 100'? – nicola

+0

@nicola problemin bağlamı biraz farklıdır; Ben esasları olduğuna inandığım şeyi çoğaltmak için bunu seçtim. Bu, benim gerçek kullanımda, 'break' bir çağrı içinde gönderilir dedi. [.data.table' – MichaelChirico

+0

Belki de içeriği daha iyi açıklamak yararlı olacaktır, çünkü burada açık bir çevre sorunu var: ”(TRUE) ile birlikte (l, break) 'aynı hatayı üretir. Görünüşe göre 'ile', R’nin“ kırılmayı ”beklemediği bir ortam yaratır. – nicola

cevap

3

bir varyantı @ Vongo'nun önerisi, değerlendirmenin environment() ile gerçekleşmesi gereken ortamı yakalamak ve'a sahip olmak için evalq()'u kullanmaktır.doğru yerde değerlendirildi.

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

Bu bir metin dizesi ayrıştırma önler ve az hacky bu nedenle görünüyor. Yakalanan ortamda değerlendirmek env döngüsünün sadece .GlobalEnv'de değil, R kodunda herhangi bir seviyede olmasını sağlar. Bu, kod hakkında akıl yürütmeyi zorlaştıran yerel olmayan bir sıçrama (aka GOTO) gibidir.

+0

ayrıca "evalq (break, parent.env (environment()))'. Yanlış çevreye "break" gönderildiyse, orijinal kodun neden sonsuz bir döngü olmadığından emin değilim. Herhangi bir nedenle? – MichaelChirico

+0

@MichaelChirico env = hakkında daha iyi açık olmak daha iyidir, çünkü arama yapan kişi çağrı yığınını yanlışlıkla değiştirebileceğinden, arama için yığın yığınının sırasına güvenmek yerine.Orijinal kod bir hata oluşturdu ve hatanın sonucu olarak döngü sona erdi. –

+0

Ohh bu mükemmel bir anlam ifade ediyor. – MichaelChirico

1

Sorunun bütün hisselerini anlamıyorum ama deneyebilirsiniz:


Ben sessionInfo() ilgili olabilecek varsayalım ait

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

Üzgünüm, sadece geri geliyor . Bence Morgan bu yaklaşımı açıkladı ve hatta geliştirdi. Kudos! – Vongo