2017-03-30 71 views
1

我試圖讓一個函數工廠使用自定義形式參數名稱來創建函數。這個想法是向工廠提供一個字符串,而這個字符串又將其替換爲返回函數的形式和主體。我已經設法使用eval(parse(text = paste()))來做到這一點,但我在其他地方看到這個不好的做法。我怎樣才能得到相同的輸出,同時避免做evalparse?在函數工廠中替換形式參數r

MyLinearRateFunctions<-function(varX){ 

    eval(parse(text=paste("function(a,b,", 
        varX, 
        ") 1/(a + b*", 
        varX, 
        ")",sep="") 
)) 

} 

(LinearRateMPG<-MyLinearRateFunctions('mpg')) 

# function(a,b,mpg) 1/(a + b*mpg) 
# <environment: 0x11c2f2a00> 

(LinearRateCYL<-MyLinearRateFunctions('cyl')) 

# function(a,b,cyl) 1/(a + b*cyl) 
# <environment: 0x11e4cb908> 

(LinearRateDISP<-MyLinearRateFunctions('disp')) 

# function(a,b,disp) 1/(a + b*disp) 
# <environment: 0x11e47eae8> 

回答

1

有可能是一個更簡潔的方式到那裏,但這裏有一個想法:

fn <- function(x) { 
    f <- eval(bquote(function(a, b) 1/(a + b * .(as.name(x))))) 
    formals(f) <- c(formals(f), setNames(alist(dummy =), x)) 
    f 
} 

fn()第一線,我們使用bquote()替代x成數學表達式。我們需要評估(通過eval())將其從呼叫轉變爲功能。然後在第二行中,我們將第三個參數添加到正式參數列表中。最後一行返回該函數。

fn("mpg") 
# function (a, b, mpg) 
# 1/(a + b * mpg) 
# <environment: 0x4f05c78> 

fn("cyl") 
# function (a, b, cyl) 
# 1/(a + b * cyl) 
# <environment: 0x4f9ba28> 

快速檢查:

fn("mpg")(1, 2, 3) 
# [1] 0.1428571 
1/(1 + 2 * 3) 
# [1] 0.1428571 

,感謝您提出一個更好的選擇,以eval(parse(text = ...)),那絕對是實踐。

+0

功能環境可以在'的eval()來改變',如果必要的話。 –

1

以下是使用pryr::make_function的替代方案。這已經設置功能「環境」的「函數工廠」的調用環境的好處調用

fn2 <- function(x) { 
    fbody <- bquote(1/(a + b * .(as.name(x)))) 
    fargs <- setNames(alist(,,),c('a','b',x)) 
    pryr::make_function(fargs,fbody, env=parent.frame(2)) 
} 

雖然這看起來像它避免了eval一個電話,它只是隱藏在make_function

1

這隻使用基礎R,並沒有eval。首先設置一個函數作爲模板,然後更改形式,設置主體並設置環境。

factory <- function(x, envir = parent.frame()) { 
    fun <- function(a, b, x) {} 
    names(formals(fun))[[3]] <- x 
    body(fun) <- substitute(1/(a+b*x), list(x = as.name(x))) 
    environment(fun) <- envir 
    fun 
} 

# test 
myfun <- factory("m") 

,並提供:

> myfun 
function (a, b, m) 
1/(a + b * m)