2016-03-23 19 views
6

Tôi gặp sự cố khi nhận vòng lặp while(TRUE) để hoạt động. Ví dụ này tôi nghĩ được tại mấu chốt của vấn đề:trong khi TRUE + ngắt trong môi trường phụ

l <- list(x = 5) 

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

nào chạy với lỗi:

Error in eval(expr, envir, enclos) :

no loop for break/next, jumping to top level

Kỳ lạ thay, while vòng dường như đã thực hiện thành công:

l 
# $x 
# [1] 105 

Nó xuất hiện vấn đề là tôi gửi câu lệnh break trong môi trường phụ, vì các công trình sau đây hoạt động như mong đợi mà không có lỗi:

x = 5 

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

Suy nghĩ nó chỉ là một vấn đề môi trường, tôi cũng đã cố gắng thay thế break với eval(break, parent.env())eval(break, parent.frame()), vô ích.

Làm cách nào để ngăn chặn lỗi này?


Tôi cho rằng sessionInfo() có thể liên quan:

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

Có lý do nào để sử dụng 'với' không? Tại sao không chỉ 'if (l $ x> 100) phá vỡ khác l $ x <-l $ x + 100'? – nicola

+0

@nicola bối cảnh của vấn đề hơi khác; Tôi đã chọn điều này để tái tạo những gì tôi tin là cần thiết. Điều đó nói rằng, trong cách sử dụng thực tế của tôi, 'break' được gửi trong một cuộc gọi đến' [.data.table' – MichaelChirico

+0

Có thể giải thích rõ hơn ngữ cảnh sẽ hữu ích, vì ở đây rõ ràng là một vấn đề môi trường: 'while (TRUE) với (l, ngắt) 'tạo ra cùng một lỗi. Rõ ràng 'with' tạo ra một môi trường mà từ đó R không mong đợi để' phá vỡ'. – nicola

Trả lời

3

Một biến thể của @ Đề nghị của Vongo là chụp môi trường mà việc đánh giá được cho là xảy ra với environment(), và sau đó sử dụng evalq() để có break được đánh giá ở đúng nơi.

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

Điều này tránh phân tích cú pháp chuỗi văn bản và có vẻ vì lý do đó ít bị hack. Đánh giá trong môi trường bị bắt env cho phép vòng lặp ở bất kỳ cấp nào trong mã R, không chỉ trong .GlobalEnv. Điều này giống như một bước nhảy phi địa phương (hay còn gọi là GOTO) khiến cho việc viết mã trở nên khó khăn hơn.

+0

cũng 'evalq (break, parent.env (environment()))'. Tôi vẫn không chắc tại sao mã gốc không phải là một vòng lặp vô hạn nếu 'ngắt' được gửi đến môi trường sai. Có lý do gì không? – MichaelChirico

+0

@MichaelChirico tốt hơn để được rõ ràng về env = thay vì dựa vào thứ tự của ngăn xếp cuộc gọi để khám phá, vì các lập trình viên vô tình có thể thay đổi ngăn xếp cuộc gọi.Mã ban đầu đã tạo ra lỗi và do hậu quả của lỗi mà vòng lặp kết thúc. –

+0

Ohh có ý nghĩa hoàn hảo. – MichaelChirico

1

Có lẽ tôi không hiểu tất cả các cổ phần của vấn đề, nhưng bạn có thể thử:

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

Xin lỗi, vừa quay lại . Tôi nghĩ rằng @ Martin Morgan đã giải thích cách tiếp cận này và thậm chí còn cải thiện nó. Kudo! – Vongo

Các vấn đề liên quan