2017-03-09 107 views
3

我需要用很多不同的參數來構建很多函數,儘管它們共享很多代碼和結構。爲了避免重複,我認爲我會很聰明,並建立自己的功能工廠(aka closure)。如何將參數(名稱)傳遞給函數工廠?

我無法弄清楚如何通過功能工廠內部函數的參數。

我的用例是一堆S3構造函數,它們都共享相同的驗證機制。 所以我將以此爲例來解釋我的問題。

說,我有一個ClassAClassB,每一個都需要在各自的構造函數自己的論點:

ClassA <- function(A_arg1, A_arg2) { 
    # some class-SPECIFIC construction magic happens, say 
    out <- list(A_arg1, A_arg2) 

    # some GENERAL construction magic happens 
    class(out) <- "ClassA" 

    return(out) 
} 

ClassB <- function(B_arg1, B_arg2) { 
    # some class-SPECIFIC construction magic happens, say 
    out <- B_arg1 + B_arg2 

    # some GENERAL construction magic happens 
    class(out) <- "ClassB" 

    return(out) 
} 

很顯然,我很想避免的一般部分重複這可以像這樣使用的構造函數,因此函數工廠將是不錯:

ClassA <- produce_class_constructor(classname = "ClassA", fun = function(A_arg1, A_arg2) {return(list(A_arg1, A_arg2))}) 

這個建議立即進行刪除d,理想情況下,產生與上述手動構建的功能完全相同的功能,其中一般部分被分解。

這是我在構建功能工廠嘗試:

produce_class_constructor <- function(classname, fun) { 
    class_specific_arguments <- formals(fun = fun) # this works just fine on the console 
    construct_class <- function(class_specific_arguments) { 
    # here runs the class-specific stuff 
    out <- fun(class_specific_arguments) 

    # here runs the general stuff 
    class(out) <- classname 
    } 
} 

然而,這是不行的,因爲由此產生的構造函數只有一個class_specific_arguments -argument,不,好,實際A_arg1A_arg2

有沒有辦法做到這一點? 我做錯了嗎?

(這對我來說非常重要,因爲生成的類構造函數具有正確命名的參數,所以...方法將不起作用)。

+0

我添加了一個類似的問題,我試圖找出如何[解決與函數操作符相同的問題](https://stackoverflow.com/questions/45923632/how-can-i-pass-argument名稱 - 功能 - 運營商 - 點 - 自由編程)aka *無點*功能編程。也許更優雅。 – maxheld

回答

1

這裏是我的嘗試:

produce_class_constructor <- function(classname, fun) { 
    out_fun <- function() { 
    out_obj <- do.call(fun, as.list(environment())) 
    class(out_obj) <- classname 
    out_obj 
    } 
    formals(out_fun) <- formals(fun) 
    out_fun 
} 

ClassA <- produce_class_constructor(classname = "ClassA", 
    fun = function(A_arg1, A_arg2) {list(A_arg1, A_arg2)}) 
ClassA(1, 2) 
#[[1]] 
#[1] 1 
# 
#[[2]] 
#[1] 2 
# 
#attr(,"class") 
#[1] "ClassA" 

ClassB <- produce_class_constructor(classname = "ClassB", 
    fun = function(B_arg1, B_arg2) {B_arg1 + B_arg2}) 
ClassB(B_arg2 = 2, 1) 
#[1] 3 
#attr(,"class") 
#[1] "ClassB" 

理念與as.list(environment())this question拍攝。請注意,您應該特別注意沿着該路徑,因爲?formals說,「這是 先進的危險編碼」。

+0

啊太棒了,非常感謝,這完成了工作。 你@tonytonov或其他人知道*爲什麼*這被認爲是「危險的」和/或有另一個更安全的建議來完成這件事? – maxheld

+1

@maxheld不客氣。那麼到目前爲止,這並不是非常危險,但重要的是,擺弄「身體」和「形式」並不是一件微不足道的事情。這是模糊的:下週給我看這個片段,我可能不會理解它的目的。維護起來很困難,你可能會在後期的開發階段期待一些怪癖(比如說,如果你需要'''''''會需要額外的工作。'在構造函數中的支持等)。這並不意味着這條路很糟糕;對於像你這樣的任務來說,這很好,只是不要嘗試實現你自己完全面向對象的類系統:) – tonytonov

相關問題