我正在递归地构造一个近似函数(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中进行递归函数构建,除了通过引用/解析的丑陋黑客
答案 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!