2013-01-18 13 views
23

अद्यतन 2 @G। ग्रोथेंडिक ने दो दृष्टिकोण पोस्ट किए। दूसरा एक फ़ंक्शन के अंदर फ़ंक्शन वातावरण बदल रहा है। यह बहुत अधिक कोडिंग प्रतिकृतियों की मेरी समस्या हल करता है। मुझे यकीन नहीं है कि पैकेज में मेरी स्क्रिप्ट बनाने के दौरान सीआरएएन जांच से गुज़रने के लिए यह एक अच्छी विधि है। जब मेरे पास कुछ निष्कर्ष हैं तो मैं फिर से अपडेट करूंगा।आर में, इस फ़ंक्शन के अंदर निचले स्तर के फ़ंक्शन पर उपलब्ध फ़ंक्शन के अंदर चर बनाने के लिए कैसे? (के साथ, संलग्न, पर्यावरण)

अद्यतन

मैं f2 के लिए इनपुट तर्क चर का एक बहुत पारित करने के लिए कोशिश कर रहा हूँ और है env$c, env$d, env$calls के रूप में समारोह के अंदर हर चर सूचकांक नहीं चाहता, यही वजह है कि मैं f5 और f6 में with का उपयोग करने की कोशिश की (एक संशोधित f2)। हालांकि, assign{} अंदर with साथ काम नहीं करता, बाहर withassign चलती काम करेगा लेकिन मेरा असली मामले में मैं जो मैं कितनी आसानी से with समारोह से बाहर उन्हें स्थानांतरित करने नहीं जानते with भाव अंदर कुछ assign रों है । ,

## In the <environment: R_GlobalEnv> 
a <- 1 
b <- 2 
f1 <- function(){ 
    c <- 3 
d <- 4 
f2 <- function(P){ 
    assign("calls", calls+1, inherits=TRUE) 
    print(calls) 
    return(P+c+d) 
} 
calls <- 0 
v <- vector() 
for(i in 1:10){ 
    v[i] <- f2(P=0) 
    c <- c+1 
    d <- d+1 
    } 
return(v) 
} 
f1() 

समारोह f2f1 अंदर है, जब f2 कहा जाता है यह पर्यावरण environment(f1) में चर calls,c,d के लिए लग रहा है:

यहाँ एक उदाहरण है। मुझे यही चाहिए था।

हालांकि, जब मैं f2 का उपयोग अन्य कार्यों में भी करना चाहता हूं, तो मैं इस समारोह को वैश्विक वातावरण में परिभाषित कर दूंगा, इसे f4 पर कॉल करें।

f4 <- function(P){ 
    assign("calls", calls+1, inherits=TRUE) 
    print(calls) 
    return(P+c+d) 
} 

यह काम नहीं करेगा क्योंकि यह वैश्विक वातावरण में के बजाय एक समारोह जहां समारोह कहा जाता है के अंदर calls,c,d के लिए दिखेगा। उदाहरण के लिए:

f3 <- function(){ 
    c <- 3 
    d <- 4 
    calls <- 0 
    v <- vector() 
    for(i in 1:10){ 
    v[i] <- f4(P=0) ## or replace here with f5(P=0) 
    c <- c+1 
    d <- d+1 
    } 
    return(v) 
} 
f3() 

सुरक्षित तरीका f4 के इनपुट बहस में calls,c,d को परिभाषित किया जाना चाहिए और फिर f4 में इन मानकों गुजरती हैं। हालांकि, मेरे मामले में, इस फ़ंक्शन f4 में पारित होने के लिए बहुत सारे चर हैं और यह बेहतर होगा कि मैं इसे पर्यावरण के रूप में पास कर सकूं और f4 वैश्विक पर्यावरण (environment(f4)) में न देखें, केवल environment के अंदर देखें जब f3 कहा जाता है।

जिस तरह से मैं इसे हल करता हूं, वह पर्यावरण को एक सूची के रूप में उपयोग करना और with फ़ंक्शन का उपयोग करना है।

f5 <- function(P,liste){ 
    with(liste,{ 
    assign("calls", calls+1, inherits=TRUE) 
    print(calls) 
    return(P+c+d) 
    } 
) 
} 
f3 <- function(){ 
    c <- 3 
    d <- 4 
    calls <- 0 
    v <- vector() 
    for(i in 1:10){ 
    v[i] <- f5(P=0,as.list(environment())) ## or replace here with f5(P=0) 
    c <- c+1 
    d <- d+1 
    } 
    return(v) 
} 
f3() 

हालांकि, अब assign("calls", calls+1, inherits=TRUE) के रूप में यह assign के बाद से होना चाहिए मूल वस्तु संशोधित नहीं करता है काम नहीं करता। परिवर्तनीय calls एक अनुकूलन समारोह से जुड़ा हुआ है जहां उद्देश्य कार्य f5 है। इनपुट तर्क के रूप में calls पास करने के बजाय assign का उपयोग करने का यही कारण है। attach का उपयोग करना मुझे भी स्पष्ट नहीं है।

f7 <- function(P,calls,liste){ 
    ##calls <<- calls+1 
    ##browser() 
    assign("calls", calls+1, inherits=TRUE,envir = sys.frame(-1)) 
    print(calls) 
    with(liste,{ 
    print(paste('with the listed envrionment, calls=',calls)) 
    return(P+c+d) 
    } 
) 
} 
######## 
################## 
f8 <- function(){ 
    c <- 3 
    d <- 4 
    calls <- 0 
    v <- vector() 
    for(i in 1:10){ 
    ##browser() 
    ##v[i] <- f4(P=0) ## or replace here with f5(P=0) 
    v[i] <- f7(P=0,calls,liste=as.list(environment())) 
    c <- c+1 
    d <- d+1 
    } 
    f7(P=0,calls,liste=as.list(environment())) 
    print(paste('final call number',calls)) 
    return(v) 
} 
f8() 

मुझे यकीन है कि यह कैसे सही दिशा पर आर एम आई में किया जाना चाहिए नहीं कर रहा हूँ, खासकर जब क्रैन के माध्यम से गुजर जाँच,: यहाँ assign समस्या को दूर करने के लिए अपने तरीका है? किसी के पास इस पर कुछ संकेत हैं?

उत्तर

22

(1) कॉलर का पर्यावरण पास करें। आप स्पष्ट रूप से मूल वातावरण और अनुक्रमणिका को पारित कर सकते हैं। इस प्रयास करें:

f2a <- function(P, env = parent.frame()) { 
    env$calls <- env$calls + 1 
    print(env$calls) 
    return(P + env$c + env$d) 
} 

a <- 1 
b <- 2 
# same as f1 except f2 removed and call to f2 replaced with call to f2a 
f1a <- function(){ 
    c <- 3 
    d <- 4 
    calls <- 0 
    v <- vector() 
    for(i in 1:10){ 
     v[i] <- f2a(P=0) 
     c <- c+1 
     d <- d+1 
     } 
    return(v) 
} 
f1a() 

(2) रीसेट बुलाया समारोह के वातावरण जैसा कि यहाँ दिखाया f1b में f2b का वातावरण पुनर्स्थापित करने के लिए है:

f2b <- function(P) { 
    calls <<- calls + 1 
    print(calls) 
    return(P + c + d) 
} 

a <- 1 
b <- 2 
# same as f1 except f2 removed, call to f2 replaced with call to f2b 
# and line marked ## at the beginning is new 
f1b <- function(){ 
    environment(f2b) <- environment() ## 
    c <- 3 
    d <- 4 
    calls <- 0 
    v <- vector() 
    for(i in 1:10){ 
     v[i] <- f2b(P=0) 
     c <- c+1 
     d <- d+1 
     } 
    return(v) 
} 
f1b() 

(3) मैक्रो eval.parent का उपयोग कर (स्थानापन्न (...)) फिर भी एक और दृष्टिकोण एक मैक्रो-जैसे निर्माण को परिभाषित करना है जो प्रभावी रूप से f2c के शरीर को f1c1 में इंजेक्ट करता है। f2cf2b जैसा calls <- calls + 1 लाइन (<<- आवश्यक) को छोड़कर eval.parent(substitute({...})) में पूरे शरीर की रैपिंग को छोड़कर f2b जैसा ही है। f1cf1a के समान है f2a पर कॉल को छोड़कर f2c पर कॉल के साथ प्रतिस्थापित किया गया है।

f2c <- function(P) eval.parent(substitute({ 
    calls <- calls + 1 
    print(calls) 
    return(P + c + d) 
})) 

a <- 1 
b <- 2 
f1c <- function(){ 
    c <- 3 
    d <- 4 
    calls <- 0 
    v <- vector() 
    for(i in 1:10){ 
     v[i] <- f2c(P=0) 
     c <- c+1 
     d <- d+1 
     } 
    return(v) 
} 
f1c() 

(4) defmacro यह लगभग पिछले समाधान के रूप में एक ही है, सिवाय इसके कि यह gtools पैकेज में defmacro का उपयोग करता है बल्कि यह ourself कर की तुलना में मैक्रो निर्धारित करने की। (अन्य डीफैमक्रो संस्करण के लिए आरसीएमडीआर पैकेज भी देखें।) defmacro काम करने के तरीके के कारण हमें calls भी पास करना होगा, लेकिन इसके बाद से यह एक मैक्रो और एक समारोह नहीं है, यह सिर्फ calls को प्रतिस्थापित करने के लिए कहता है और calls को पास करने के समान नहीं है समारोह।

library(gtools) 

f2d <- defmacro(P, calls, expr = { 
    calls <- calls + 1 
    print(calls) 
    return(P + c + d) 
}) 

a <- 1 
b <- 2 
f1d <- function(){ 
    c <- 3 
    d <- 4 
    calls <- 0 
    v <- vector() 
    for(i in 1:10){ 
     v[i] <- f2d(P=0, calls) 
     c <- c+1 
     d <- d+1 
     } 
    return(v) 
} 
f1d() 
+0

यह परिणाम मुझे देता है लेकिन मैंने स्पष्ट रूप से मेरा अनुरोध नहीं लिखा है। असल में, मैं 'f2' में गुजरने वाले सभी चरों को इंडेक्स से बचना चाहता हूं, यानी, 'env $' लिखना नहीं, इसलिए मैंने 'with' का उपयोग करने का प्रयास किया। मैं 'f2' के अंदर बाहरी 'कॉल' को संशोधित करने में सक्षम होना चाहता हूं लेकिन वर्तमान वातावरण में अन्य चर को नहीं बदलना चाहता हूं। मैं सवाल अपडेट करूंगा। – Zhenglei

+0

मैंने एक दूसरा दृष्टिकोण जोड़ा है। –

+0

ऐसा लगता है कि मुझे क्या चाहिए। मैं इसे अपने असली मामले के साथ परीक्षण करूँगा और बाद में अपडेट करूंगा। मदद के लिए बहुत - बहुत धन्यवाद! – Zhenglei

1

सामान्य रूप से, मैं कहूंगा कि किसी भी चर के लिए आवश्यक किसी भी चर को इसके तर्कों के माध्यम से पारित किया जाना चाहिए। इसके अतिरिक्त, यदि इसके मूल्य की आवश्यकता है तो बाद में आप इसे फ़ंक्शन से वापस भेज दें। ऐसा नहीं कर सकता है अजीब परिणाम, जैसे उदा। क्या होगा यदि एक चर x को परिभाषित करने वाले कई फ़ंक्शन हैं, जिनका उपयोग किया जाना चाहिए। यदि चर की मात्रा बड़ी है, तो आप इसके लिए एक कस्टम डेटा संरचना बनाते हैं, उदा। उन्हें एक नामित सूची में डाल दिया।

+0

मैं आम तौर पर आपके साथ @ पॉल से सहमत हूं। मैं अपने कोड को आर पैकेज बनाने की कोशिश कर रहा हूं लेकिन ग्लोबल वैरिएबल बाइंडिंग जैसी कई चेतावनियों के साथ आसानी से सीआरएएन जांच से गुजर नहीं सकता हूं। कई बार दोहराए गए कोड हैं क्योंकि 'f2' को फ़ंक्शन के अंदर परिभाषित किया गया है और मैं इसे किसी अन्य नए फ़ंक्शन में उपयोग करना चाहता हूं। मुझे एहसास है कि कॉपी पेस्ट यह एक अच्छा विकल्प नहीं है और बाद के चरणों में समस्याएं पैदा कर सकता है। मैं भी प्रयास को कम करना चाहता हूं क्योंकि मैं पहले से ही मौजूदा स्क्रिप्स को बहुत ज्यादा नहीं बदलना चाहता हूं। यही कारण है कि मैं एक नई डेटा संरचना को परिभाषित करने के बजाय पर्यावरण को पारित करने का प्रयास करता हूं। – Zhenglei

1

कोई भी उस फ़ंक्शन का उपयोग कर सकता है जो निर्दिष्ट वातावरण में अन्य कार्यों को फिर से परिभाषित करता है।

test_var <- "global" 

get_test_var <- function(){ 
    return(test_var) 
} 

some_function <- function(){ 
    test_var <- "local" 
    return(get_test_var()) 

} 

some_function() # Returns "global". Not what we want here... 

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

some_function2 <- function(){ 
    test_var <- "local" 
    # define function locally 
    get_test_var2 <- function(){ 
    return(test_var) 
    } 
    return(get_test_var2()) 
} 

some_function2() # Returns "local", but 'get_test_var2' can't be used in other places. 

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

add_function_to_envir <- function(my_function_name, to_envir) { 
    script_text <- capture.output(eval(parse(text = my_function_name))) 
    script_text[1] <- paste0(my_function_name, " <- ", script_text[1]) 
    eval(parse(text = script_text), envir = to_envir) 
} 

some_function3 <- function(){ 
    test_var <- "local" 
    add_function_to_envir("get_test_var", environment()) 
    return(get_test_var()) 
} 

some_function3() # Returns "local" and we can use 'get_test_var' from anywhere. 

यहाँ add_function_to_envir(my_function_name, to_envir) समारोह की पटकथा कैप्चर करता है, पार्स करके नए माहौल में यह पुन: मूल्यांकन।

नोट: my_function_name के लिए फ़ंक्शन का नाम उद्धरणों में होना चाहिए।

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