2010-06-29 16 views
5

मैं एक ऐसा फ़ंक्शन बनाना चाहता हूं जो अभिव्यक्ति को फिर से विफल कर देगा।आर रिकर्सिव अभिव्यक्ति पर चेतावनी संदेश: यदि आप असफल होते हैं, तो कोशिश करें, पुनः प्रयास करें

retry <- function(.FUN, max.attempts=3, sleep.seconds=1) { 
    x <- NULL 
    if(max.attempts > 0) { 
    f <- substitute(.FUN) 
    x <- try(eval(f)) 
    if(class(x) == "try-error") { 
     Sys.sleep(sleep.seconds) 
     return(suppressWarnings(retry(.FUN, max.attempts-1))) 
    } 
    } 
    x 
} 

retry(stop("I'm here")) 

अगर मैं suppressWarnings() समारोह ऊपर निकालें, तब मैं प्रत्येक पुनरावर्ती फोन पर चेतावनी का एक सेट प्राप्त करें: यहाँ मेरी काम कर संस्करण है। क्या किसी को पता है कि मैं गलत क्या कर रहा हूं जिससे इसका कारण होगा?

यहाँ एक उदाहरण है कि बार-बार चलाया जा सकता है है:

retry({ tmp <- function() { if(rnorm(1) < 0) stop("I'm here") else "success" }; tmp() }) 

उत्तर

6

मुझे यकीन है कि अगर मैं कारण वास्तव में वर्णन कर सकते हैं नहीं कर रहा हूँ, लेकिन मैं इस समस्या को अलग किया गया है और इसे ठीक कर सकते हैं। मूल समस्या रिकर्सन है: retry(.FUN, max.attempts-1) - जब रिकर्सिव कॉल substitute(.FUN) पर कॉल करता है तो यह पता लगाने के लिए कॉल स्टैक का एक स्तर ऊपर जा रहा है कि .FUN का मूल्य क्या है - इसे एक वादे के मूल्यांकन को पुनरारंभ करना होगा (देरी निष्पादन कार्य तर्क के) एक स्तर ऊपर।

retry <- function(.FUN, max.attempts = 3, sleep.seconds = 0.5) { 
    expr <- substitute(.FUN) 
    retry_expr(expr, max.attempts, sleep.seconds) 
} 

retry_expr <- function(expr, max.attempts = 3, sleep.seconds = 0.5) { 
    x <- try(eval(expr)) 

    if(inherits(x, "try-error") && max.attempts > 0) { 
    Sys.sleep(sleep.seconds) 
    return(retry_expr(expr, max.attempts - 1)) 
    } 

    x 
} 

f <- function() { 
    x <- runif(1) 
    if (x < 0.5) stop("Error!") else x 
} 

retry(f()) 

कार्यों है कि आप लचीलेपन का उपयोग कर सकते बनाने के लिए, मैं अत्यधिक विकल्प के उपयोग को कम करने की सिफारिश:

फिक्स सिर्फ एक बार प्रतिस्थापन करना है। मेरे अनुभव में, आप आमतौर पर एक ऐसा कार्य करने से सबसे अच्छे होते हैं जो प्रतिस्थापन करता है, और दूसरा जो सभी काम करता है। यह किसी अन्य फ़ंक्शन से कॉल किए जाने पर फ़ंक्शन का उपयोग करना संभव बनाता है:

g1 <- function(fun) { 
    message("Function starts") 
    x <- retry(fun) 
    message("Function ends") 
    x 
} 
g1(f()) 
# Function starts 
# Error in eval(expr, envir, enclos) : object 'fun' not found 
# Error in eval(expr, envir, enclos) : object 'fun' not found 
# Error in eval(expr, envir, enclos) : object 'fun' not found 
# Error in eval(expr, envir, enclos) : object 'fun' not found 
# Function ends 

g2 <- function(fun) { 
    message("Function starts") 
    expr <- substitute(fun) 
    x <- retry_expr(expr) 
    message("Function ends") 
    x 
} 
g2(f()) 
# Function starts 
# Error in f() : Error! 
# Function ends 
# [1] 0.8079241 
+0

मैंने सोचा होगा कि आपके संस्करण में एफयूएन का रिकर्सिव निष्पादन काम नहीं करेगा क्योंकि उस बिंदु पर एफयूएन का मूल्यांकन पहले से ही किया जाएगा? मैं इसका परीक्षण करूंगा ... – Shane

+0

मुझे लगता है कि आप सही हैं, लेकिन इस बीच मैंने इसे समझ लिया। मुझे लगता है कि मेरा एफ एक बेहतर उदाहरण है क्योंकि कभी-कभी यह त्रुटियां होती है और कभी-कभी यह नहीं होती है। यह जांचने के लिए कुछ बार चलाएं कि यह वही करता है जो आप उम्मीद करते हैं। मुझे यकीन नहीं है कि जब आप प्रयासों से बाहर निकलते हैं तो आप वापस लौटना चाहते थे लेकिन अभी भी एक त्रुटि है। – hadley

+0

ओह, मुझे लगता है कि आपके पोस्ट के नीचे मेरे एफ के बराबर था:/ – hadley

3

आप चेतावनी क्यों मिलता है के बारे में सुनिश्चित नहीं हैं ... लेकिन एक for पाश वे गायब हो का उपयोग करें।

retry <- function(.FUN, max.attempts=3, sleep.seconds=1) 
    { 
    x <- NULL 
    for (i in 1:max.attempts) 
     { 
     f <- substitute(.FUN) 
     x <- try(eval(f)) 
     if (class(x) == "try-error") 
     { 
     Sys.sleep(sleep.seconds) 
     } 
     else 
     { 
     return (x) 
     } 
     } 
    x 
    } 
+0

धन्यवाद @ एनिको; मैं अधिकतर उत्सुक था कि विकल्प के साथ चेतावनियां क्या कर रही थीं। लेकिन आपका संस्करण पूरी तरह से काम करता है! – Shane

संबंधित मुद्दे