在R中累积函数和闭包

时间:2013-08-11 03:33:06

标签: r closures

我正在递归地构造一个近似函数(adaboost)。我想在此过程中创建生成的学习函数(不是将近似直接应用于我的测试数据,而是保留导致它的函数)

不幸的是,R似乎更新了变量名在使用后很长时间所指的值。

#defined in plyr as well
id <- function(x) {x}

#my first classifier 
modelprevious <- function(inputx, k) { k(0)}

#one step of my superb model
modelf <- function(x) 2*x #for instance

#I update my classifier
modelCurrent <- function(inputx, k) 
                 { modelprevious(inputx, function(res) {k(res + modelf(inputx))})}

#it works
modelCurrent(2,id) #4

#Problem
modelf <- function(x) 3*x
modelCurrent(2,id) #6 WTF !! 

具有相同参数的相同函数会返回不同的内容,这非常烦人!

那么如何捕获由modelf表示的,以便生成的函数仅取决于绑定时的参数,而不是某个全局状态?


鉴于这个问题,我不知道如果一个人无法触及局部变量,如何在R中进行递归函数构建,除了通过引用/解析的丑陋黑客

1 个答案:

答案 0 :(得分:10)

你需要一家工厂:

modelCurrent = function(mf){
  return(function(inputx,k){
    modelprevious(
      inputx,
      function(res){
        k(res+mf(inputx))
      } # function(res)
      ) # modelprevious
  } # inner function
         ) # return
} # top function

现在您使用工厂创建具有您希望它使用的modelf函数的模型:

> modelf <- function(x) 2*x
> m1 = modelCurrent(modelf)
> m1(2,id)
[1] 4
> modelf <- function(x) 3*x
> m1(2,id) # no change.
[1] 4

你总是可以在临时的基础上制作它们:

> modelCurrent(modelf)(2,id)
[1] 6

在那里你可以看到工厂使用modelf的当前定义创建了一个函数,所以它乘以3。

最后一个巨大的WTF!?!会打你的。仔细观察:

> modelf <- function(x) 2*x
> m1 = modelCurrent(modelf)
> m1(2,id)
[1] 4
>
> m1 = modelCurrent(modelf) # create a function using the 2* modelf
> modelf <- function(x) 3*x # change modelf...
> m1(2,id) # WTF?!
[1] 6

这是因为调用工厂时,mf未被评估 - 这是因为未调用内部函数,并且在调用内部函数之前不使用mf。 / p>

诀窍是强制评估外部函数中的mf,通常使用force

modelCurrent = function(mf){
  force(mf)
  return(function(inputx,k){
    modelprevious(
      inputx,
      function(res){
        k(res+mf(inputx))
      } # function(res)
      ) # modelprevious
  } # inner function
         ) # return
} # top function

这导致我过早秃顶,因为如果你忘了这一点,并认为有一些奇怪的错误正在发生,然后尝试坚持print(mf)到位,看看发生了什么,你将评估{{1从而得到你想要的行为。通过检查数据,你改变了它!一个Heisenbug!