आर

2013-05-11 4 views
5

में फ़ंक्शन बॉडी के रूप में अभिव्यक्ति को कैप्चर करना मैं एक प्रोग्राम लिखने की कोशिश कर रहा हूं जो इनपुट के रूप में अभिव्यक्ति लेता है और उस अभिव्यक्ति के साथ एक फ़ंक्शन देता है जो उसके शरीर के रूप में बंधे होते हैं।आर

caller <- function (expr, params) { 

    Function <- function (params, body, env = parent.frame()) { 
     # returns a function 

    } 

    Function(params, body = expr) 
} 

func <- caller (a + b, c('a', 'b')) 

func(1, 2) 
[1] 3 

मैं की तरह

params <- c('a', 'b') 
f <- function() {} 
formals(f) <- structure(
    replicate(length(params), NULL), 
    names = params 
) 

मैं मुसीबत गतिशील शरीर के रूप में अभिव्यक्ति जोड़ने का एक तरीका के साथ आ रही है काफी आसानी से मानकों को बाध्य कर सकते हैं, कुछ का उपयोग करके। मैंने विकल्प() का उपयोग करने की कोशिश की है, और pryr लाइब्रेरी से make_function को अपनाना है, लेकिन मुझे काम करने के लिए काफी कुछ नहीं मिल सकता है। मेरा सबसे अच्छा प्रयास

body(f, parent.frame()) <- as.list(match.call())[-1]$body 

मैं इसे विकल्प के साथ काम करने के लिए नहीं मिला। शरीर को बांधने के तरीके पर कोई विचार है कि शीर्ष कार्यक्रम अपेक्षित काम करता है?

मैंने SO पर similar questions देखा है, लेकिन समाधान इस समस्या को सफ़ल नहीं लगते हैं।

उत्तर

3

यहां पैरामीटर को डिफ़ॉल्ट मान के बिना अनुमति देने का एक समाधान है। पैरामीटर नामों को पार करना भी आसान है, क्योंकि उन्हें उद्धरणों के साथ संलग्न नहीं होना चाहिए।

नीचे कोड में टिप्पणी की जाँच करें:

g <- function(...) 
{ 
    # Get the arguments as unevaluated expressions: 

    L <- as.list(substitute(list(...)))[-1] 

    # The first argument is the body expression (technically a call object): 

    expr <- L[[1]] 

    # If the expression is not enclosed in curly braces, let's force it: 

    if(as.character(expr[[1]]) != "{") expr <- call("{", expr) 

    # Drop the first argument: 

    L <- L[-1] 

    # Mark symbols to be used as names for missing parameters: 

    filter <- vapply(L, is.symbol, logical(1)) 

    params <- L 

    # The obscure expression "formals(function(x){})$x" returns a missing value, something really arcane ;-) : 

    params[filter] <- list(formals(function(x){})$x) 

    # Here the symbols are used as names: 

    names(params)[filter] <- vapply(L[filter], as.character, character(1)) 

    # Now the result: 

    f <- function(){} 

    formals(f) <- params 

    body(f) <- expr 

    # Just to make it nicier, let's define the enclosing environment as if the function were created outside g: 

    environment(f) <- parent.frame() 

    f 
} 

कुछ परीक्षण:

> g(a+b, a, b=1) 
function (a, b = 1) 
{ 
    a + b 
} 


> f <- g({x <- a+b; x^2}, a, b) 
> f 
function (a, b) 
{ 
    x <- a + b 
    x^2 
} 
> f(2,3) 
[1] 25 
> f(1) 
Error in a + b : 'b' is missing 

> g(a+b, a=2, b=2)() 
[1] 4 
+0

धन्यवाद :) मुझे डिफ़ॉल्ट तर्क के बिना पैरा जोड़ने के लिए आपका समाधान पसंद है – RyanGrannell

+0

ऐसा लगता है कि 'g (a + b, a, b = a) 'काम नहीं करता है क्योंकि आपका कोड दूसरे फ़ंक्शन तर्क को केवल' ए 'में बदल देता है । मुझे लगता है कि किसी भी नामित तर्क को बदलने के लिए बेहतर होगा। –

4

कैसे के बारे में बस:

caller <- function(expr, params) { 
    f <- function() NULL 
    formals(f) <- structure(replicate(length(params), NULL), names=params) 
    body(f, envir=parent.frame()) <- substitute(expr) 
    f 
} 

यह एक आंतरिक समारोह है, जो किया गया है सकते substitute साथ अपनी समस्याओं के कारण उपयोग नहीं करता।

ध्यान दें कि मुझे यकीन नहीं है कि यह लौटाए गए कार्य के माहौल को जिस तरह से आप चाहते हैं उसे स्थापित कर रहा है। यह उस पर्यावरण को सेट करता है जहां से आप caller पर कॉल करते हैं।

+0

वहाँ 'body' में कोई दूसरा तर्क है: (च, माहौल = parent.frame()) शरीर में त्रुटि: अप्रयुक्त तर्क (ओं) (envir = parent.frame()) –

+1

@ फर्डिनेंड.क्राफ्ट: दूसरा तर्क केवल 'बॉडी' के प्रतिस्थापन रूप में है, जो 'कॉलर' का उपयोग करता है। –

+0

मुझे मिल गया! धन्यवाद! –

0

समारोह तर्क निर्दिष्ट करने के एक दिलचस्प वैकल्पिक तरीका alist समारोह के रूप में उसी प्रणाली का उपयोग करने के लिए है, जिसे आमतौर पर formals के संयोजन के साथ प्रयोग किया जाता है।

alist <- function (...) as.list(sys.call())[-1L] 

यह आसानी से caller साथ काम करने के लिए अनुकूलित किया गया है:: यह है कि यह कैसे base पैकेज में परिभाषित किया गया है

caller <- function(...) { 
    f <- function() NULL 
    formals(f) <- as.list(sys.call())[-(1:2)] 
    body(f, envir=parent.frame()) <- substitute(list(...))[[2]] 
    f 
} 

पहला तर्क अभी भी समारोह शरीर को निर्दिष्ट करता है, और शेष बहस में के रूप में ठीक उसी तरह काम alist

> func <- caller(a+b, a=, b=10) 
> func(1) 
[1] 11 
> func <- caller(a+b, a=, b=a) 
> func(10) 
[1] 20 

तुम भी कार्यों कि ... का उपयोग बना सकते हैं:

> func <- caller(c(...), ...=) 
> func("a", "b", "c") 
[1] "a" "b" "c"