2013-05-11 70 views
5

表達爲函數體我試圖寫一個程序,它的表達作爲輸入,並返回的功能與結合作爲它的主體,其表達。捕獲中的R

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,但解決方案似乎並不satistfy這個問題。

回答

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 2013-05-15 14:53:06

+0

它看起來像'g(a + b,a,b = a)'不起作用,因爲你的代碼將第二個函數參數簡單地轉換爲'a' 。我認爲最好不要改變任何命名的論點。 – 2013-05-24 14:48:19

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'沒有第二個參數:錯誤體(F,ENVIR = parent.frame()): 未使用的參數(一個或多個)(ENVIR = parent.frame()) – 2013-05-13 15:29:46

+1

@ Ferdinand.kraft:第二個參數是僅在body'的'替換形式,這是什麼'caller'使用。 – 2013-05-13 16:37:44

+0

我懂了!謝謝! – 2013-05-13 16:50:04

0

指定函數參數的一個有趣的另一種方法是使用相同的機制alist功能,它通常與formals一起使用。這是它是如何在base包中定義:

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

這是很容易適應與caller工作:

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"