[英]Proper way to have two functions access a single function's environment?
Based on the answer provided in 1088639 , I set up a pair of functions which both access the same sub-function's environment. 根据1088639中提供的答案,我设置了一对函数,它们都访问相同的子函数环境。 This example works, but I wanted to see if I'd missed some cleaner way to "connect" both top-level functions to the internal environment.
这个例子有效,但我想看看我是否错过了将两个顶层函数“连接”到内部环境的更简洁方法。
( Back story: I wanted to write a pair of complementary functions which shared a variable, eg "count" in this example, and meet CRAN package requirements which do not allow functions to modify the global environment. ) (背景故事:我想编写一对共享变量的互补函数,例如本例中的“count”, 并满足CRAN包要求,这些要求不允许函数修改全局环境。)
static.f <- function() {
count <- 0
f <- function(x) {
count <<- count + 1
return( list(mean=mean(x), count=count) )
}
return( f )
}
# make sure not to delete this command, even tho' it's not
# creating a function.
f1 <- static.f()
statfoo <- function(x){
tmp<-f1(x)
tmp<- list(tmp,plus=2)
return(tmp)
}
statbar <- function(x){
tmp<-f1(x)
tmp<- list(tmp,minus=3)
return(tmp)
}
Sample output: 样本输出:
> statfoo(5)
[[1]]
[[1]]$mean
[1] 5
[[1]]$count
[1] 1
$plus
[1] 2
Rgames> statfoo(5)
[[1]]
[[1]]$mean
[1] 5
[[1]]$count
[1] 2
$plus
[1] 2
> statbar(4)
[[1]]
[[1]]$mean
[1] 4
[[1]]$count
[1] 3
$minus
[1] 3
> statfoo(5)
[[1]]
[[1]]$mean
[1] 5
[[1]]$count
[1] 4
$plus
[1] 2
A cleaner method would be to use an object oriented approach. 更简洁的方法是使用面向对象的方法。 There is already an answer using reference classes.
已经有一个使用参考类的答案。
A typical object oriented approach with classes would create a class and then create a singleton object, ie a single object of that class. 使用类的典型面向对象方法将创建一个类,然后创建一个单例对象,即该类的单个对象。 Of course it is a bit wasteful to create a class only to create one object from it so here we provide a proto example.
当然创建一个类只是为了从它创建一个对象有点浪费,所以这里我们提供一个proto示例。 (Creating a function to enclose
count
and the function doing the real work has a similar problem -- you create an enclosing function only to run it once.) The proto model allows one to create an object directly bypassing the need to create a class only to use it once. (创建一个包含
count
的函数和执行实际工作的函数也有类似的问题 - 你创建一个封闭函数只运行一次。)proto模型允许一个人创建一个对象,直接绕过创建一个类的需要使用一次。 Here foobar
is the proto object with property count
and methods stats
, statfoo
and statbar
. 这里
foobar
是具有属性count
和方法stats
, statfoo
和statbar
的proto对象。 Note that we factored out stats
to avoid duplicating its code in each of statfoo
and statbar
. 请注意,我们考虑了
stats
以避免在statfoo
和statbar
重复其代码。 (continued further down) (继续向下)
library(proto)
foobar <- proto(count = 0,
stats = function(., x) {
.$count <- .$count + 1
list(mean = mean(x), count = .$count)
},
statfoo = function(., x) c(.$stats(x), plus = 2),
statbar = function(., x) c(.$stats(x), plus = 3)
)
foobar$statfoo(1:3)
foobar$statbar(2:4)
giving: 赠送:
> foobar$statfoo(1:3)
$mean
[1] 2
$count
[1] 1
$plus
[1] 2
> foobar$statbar(2:4)
$mean
[1] 3
$count
[1] 2
$plus
[1] 3
A second design would be to have statfoo
and statbar
as independent functions and only keep count
and stats
in foobar
(continued further down) 第二种设计是将
statfoo
和statbar
作为独立函数,只保留foobar
count
和stats
(继续向下)
library(proto)
foobar <- proto(count = 0,
stats = function(., x) {
.$count <- .$count + 1
list(mean = mean(x), count = .$count)
}
)
statfoo <- function(x) c(foobar$stats(x), plus = 2)
statbar <- function(x) c(foobar$stats(x), plus = 3)
statfoo(1:3)
statbar(2:4)
giving similar output to the prior example. 给前面的例子提供类似的输出。
Third approach Of course the second variation could easily be implemented by using local
and a function getting us close to where you started. 第三种方法当然,第二种变体可以通过使用
local
和函数轻松实现,使我们接近您开始的位置。 This does not use any packages but does not create a function only to throw it away: 这不会使用任何包,但不会创建一个函数只是扔掉它:
foobar <- local({
count <- 0
function(x) {
count <<- count + 1
list(mean = mean(x), count = count)
}
})
statfoo <- function(x) c(foobar(x), plus = 2)
statbar <- function(x) c(foobar(x), plus = 3)
statfoo(1:3)
statbar(2:4)
You can use reference class like this: 您可以使用这样的引用类:
foobar <- setRefClass(
'foobar',
fields = list(count='numeric'),
methods = list(
initialize=function() {
.self$initFields(count = 0L)
},
statfoo = function(x) {
count <<- count + 1L
list(list(mean=mean(x), count=count), plus=2)
},
statbar = function(x){
count <<- count + 1L
list(list(mean=mean(x), count=count), minus=3)
}
)
)()
foobar$statfoo(5)
foobar$statbar(3)
It makes it relatively clear that neither statfoo
nor statbar
is a pure function. 这使得相对清楚的是,
statfoo
和statbar
是纯函数。
Another simple option is tocreate an environment and assign it to both functions. 另一个简单的选择是创建一个环境并将其分配给两个函数。 Here I use simpler functions for illustrative purposes, but this can be easily extended:
这里我使用更简单的函数用于说明目的,但这可以很容易地扩展:
f1 <- function() {count <<- count + 1; return(paste("hello", count))}
f2 <- function() {count <<- count + 1; return(paste("goodbye", count))}
environment(f1) <- environment(f2) <- list2env(list(count=0))
Then: 然后:
> f1()
[1] "hello 1"
> f2()
[1] "goodbye 2"
> f1()
[1] "hello 3"
Both functions have the same environment. 两个功能都具有相同的环境。
You could get rid of the factory functions, and more explicitly use environments. 您可以摆脱工厂功能,更明确地使用环境。 A solution like this would work as well
像这样的解决方案也可以
.env<-(function() {
count <- 0
f <- function(x) {
count <<- count + 1
return( list(mean=mean(x), count=count))
}
return(environment())
})()
statfoo <- function(x){
list(.env$f(x),plus=2)
}
statbar <- function(x){
list(.env$f(x),minus=3)
}
The .env
variable is created by immediately executing an anonymous function to get its environment. .env
变量是通过立即执行匿名函数来获取其环境而创建的。 We then extract the function from the environment itself to modify its values. 然后,我们从环境本身提取函数以修改其值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.