对 R 包中的函数进行分组
Grouping functions from an R package
上下文
我正在开发一个 R 包,其中包含分为 10 个不同主题的一百多个页面长的函数。
期望的行为
我希望用户在调用函数时能够考虑到这些主题。
例如,用户不必调用 foo()
,而是必须执行任一操作
load(theme1) # or whatever would be used to load a subgroup of functions
foo()
或类似
theme1$foo()
我要防止用户不考虑主题直接加载包调用函数,即library(package); foo()
.
我试过的
我已经使用了modules package to accomplish the latter solution in a previous package, but this time around the published version of that package doesn't work very well due to how my functions are interdependent (I've opened a GitHub issue这个话题。
我也考虑过编写自己的解决方案,也许是一些简单的事情,涉及创建一个 sublibrary()
函数,一次只导出几个函数,但我没有得到任何结果。
当然,我想发布 10 个不同的包在技术上也是可行的,但我认为考虑这个解决方案太笨拙了。
问题
除了使用模块之外,有没有办法实现上述任一功能?
这里可以使用面向对象编程,其中 theme1
是一个 class 或从 class 实例化的对象,与之关联的函数是方法。这里有许多替代方案,包括 R 参考 classes(更多信息来自 ?ReferenceClasses
)、R6 package, proto package, the R.oo package 和函数范围(更多信息来自 demo("scoping")
.
例如使用原型包:
library(proto)
theme1 <- proto(
foo = function(.) print("foo"),
bar = function(.) print("bar")
)
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
如果只是分组问题,并且不需要本地存储或继承,那么我们甚至可以使用列表:
theme1 <- list(foo = function() print("foo"),
bar = function() print("bar"))
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
可以使用许多其他 OO 方法,但它们涉及创建一个 class,然后用于创建单个对象(这是一个额外的步骤);但是,他们确实支持问题的 $ 语法。
使用 R6 我们有:
library(R6)
Theme1 = R6Class("theme1",
public = list(
foo = function() print("foo"),
bar = function() print("bar")
)
)
theme1 <- Theme1$new() # generate a Theme1 object
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
或使用参考资料类(不需要包):
setRefClass(
"Theme1",
methods = list(
foo = function() print("foo"),
bar = function() print("bar")
)
)
theme1 <- Theme1() # generate Theme1 object
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
或使用函数作用域(不需要包):
Theme1 <- function() list(
foo = function() print("foo"),
bar = function() print("bar")
)
theme1 <- Theme1()
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
这里是关于如何实现 sublibrary
功能的想法。在这种情况下,我们将使用它来加载 ggplot2
的一小部分
sublibrary <- function(theme) {
subgroups <-
list(basic = list(ggplot = ggplot2::ggplot,
aes = ggplot2::aes,
geom_line = ggplot2::geom_line,
geom_point = ggplot2::geom_point),
advanced = list(scale_color_manual = ggplot2::scale_color_manual,
theme = ggplot2::theme))
attach(list2env(subgroups[[theme]]))
}
这意味着在不加载整个包的情况下我可以这样做:
sublibrary("basic")
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point()
实际上,subgroup
对象将存储在函数外部,在包命名空间内的列表或环境中。
上下文
我正在开发一个 R 包,其中包含分为 10 个不同主题的一百多个页面长的函数。
期望的行为
我希望用户在调用函数时能够考虑到这些主题。
例如,用户不必调用 foo()
,而是必须执行任一操作
load(theme1) # or whatever would be used to load a subgroup of functions
foo()
或类似
theme1$foo()
我要防止用户不考虑主题直接加载包调用函数,即library(package); foo()
.
我试过的
我已经使用了modules package to accomplish the latter solution in a previous package, but this time around the published version of that package doesn't work very well due to how my functions are interdependent (I've opened a GitHub issue这个话题。
我也考虑过编写自己的解决方案,也许是一些简单的事情,涉及创建一个 sublibrary()
函数,一次只导出几个函数,但我没有得到任何结果。
当然,我想发布 10 个不同的包在技术上也是可行的,但我认为考虑这个解决方案太笨拙了。
问题
除了使用模块之外,有没有办法实现上述任一功能?
这里可以使用面向对象编程,其中 theme1
是一个 class 或从 class 实例化的对象,与之关联的函数是方法。这里有许多替代方案,包括 R 参考 classes(更多信息来自 ?ReferenceClasses
)、R6 package, proto package, the R.oo package 和函数范围(更多信息来自 demo("scoping")
.
例如使用原型包:
library(proto)
theme1 <- proto(
foo = function(.) print("foo"),
bar = function(.) print("bar")
)
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
如果只是分组问题,并且不需要本地存储或继承,那么我们甚至可以使用列表:
theme1 <- list(foo = function() print("foo"),
bar = function() print("bar"))
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
可以使用许多其他 OO 方法,但它们涉及创建一个 class,然后用于创建单个对象(这是一个额外的步骤);但是,他们确实支持问题的 $ 语法。
使用 R6 我们有:
library(R6)
Theme1 = R6Class("theme1",
public = list(
foo = function() print("foo"),
bar = function() print("bar")
)
)
theme1 <- Theme1$new() # generate a Theme1 object
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
或使用参考资料类(不需要包):
setRefClass(
"Theme1",
methods = list(
foo = function() print("foo"),
bar = function() print("bar")
)
)
theme1 <- Theme1() # generate Theme1 object
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
或使用函数作用域(不需要包):
Theme1 <- function() list(
foo = function() print("foo"),
bar = function() print("bar")
)
theme1 <- Theme1()
theme1$foo()
## [1] "foo"
theme1$bar()
## [1] "bar"
这里是关于如何实现 sublibrary
功能的想法。在这种情况下,我们将使用它来加载 ggplot2
sublibrary <- function(theme) {
subgroups <-
list(basic = list(ggplot = ggplot2::ggplot,
aes = ggplot2::aes,
geom_line = ggplot2::geom_line,
geom_point = ggplot2::geom_point),
advanced = list(scale_color_manual = ggplot2::scale_color_manual,
theme = ggplot2::theme))
attach(list2env(subgroups[[theme]]))
}
这意味着在不加载整个包的情况下我可以这样做:
sublibrary("basic")
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point()
实际上,subgroup
对象将存储在函数外部,在包命名空间内的列表或环境中。