【发布时间】:2019-05-27 21:24:13
【问题描述】:
我很久以前在 Coursera 上的约翰霍普金斯大学 MOOC R 编程中学到了这种方法。这个想法是返回一个在父函数范围内定义的函数列表。例如:
newString <- function(s) {
l <- nchar(s)
return(list(
get = function() return(s),
len = function() return(l),
concate = function(cat) {
s <<- paste0(s, cat)
l <<- nchar(s)
},
find = function(pattern) return(grepl(pattern, s)),
substitute = function(pattern, sub) {
s <<- gsub(pattern, sub, s)
l <<- nchar(s)
}
))
}
此函数返回可以操作项目“s”的函数/方法列表。我可以“新建”这个“对象”调用父函数:
my <- newString("hellow")
并且使用 $ 的“方法”看起来就像 OOP。
my$get()
# [1] "hellow"
my$len()
# [1] 6
my$substitute("w$", "")
my$get()
# [1] "hello"
my$len()
# [1] 5
my$concate(", world")
my$get()
# [1] "hello, world"
my$find("world$")
# [1] TRUE
直接打印“对象”,我们可以看到它是一个函数列表。所有这些功能都位于同一环境0x103ca6e08,项目s也在其中。
my
# $get
# function ()
# return(s)
# <bytecode: 0x1099ac1e0>
# <environment: 0x103ca6e08>
#
# $len
# function ()
# return(l)
# <bytecode: 0x109a58058>
# <environment: 0x103ca6e08>
#
# $concate
# function (cat)
# {
# s <<- paste0(s, cat)
# l <<- nchar(s)
# }
# <bytecode: 0x1074fd4e8>
# <environment: 0x103ca6e08>
#
# $find
# function (pattern)
# return(grepl(pattern, s))
# <bytecode: 0x1076c8470>
# <environment: 0x103ca6e08>
#
# $substitute
# function (pattern, sub)
# {
# s <<- gsub(pattern, sub, s)
# l <<- nchar(s)
# }
# <bytecode: 0x1077ad270>
# <environment: 0x103ca6e08>
那么这种编程风格(?)被认为是 OOP 还是类似 OOP 的?这和S3/S4有什么区别?
感谢@G.Grothendieck、@r2evans 和@Jozef。 R 中scoping 的演示文档说“函数可以封装状态信息”,因为 R 中的范围规则。而且 RC 系统“使用环境”,所以我认为我所做的类似于原始 RC 系统。
“对象是带有函数的数据。闭包是带有数据的函数。” ——约翰·D·库克
闭包之所以得名,是因为它们封装了父函数的环境并且可以访问其所有变量。
在http://adv-r.had.co.nz/Functional-programming.html#closures 我发现最合适的名称是closure。
【问题讨论】:
-
您所做的与Functional Programming 相似。尤其要阅读关于一等和高阶函数的部分
-
试试
demo("scoping") -
adv-r.had.co.nz/OO-essentials.html 包含 S3、S4 和 RC 的不错比较。
-
@G.Grothendieck 演示正是如此!因为 R 中“函数可以封装状态信息”,所以这种编程风格实际上并不算是“函数式编程”,对吧?
-
OO 和函数式编程没有单一的含义,但
newString可以看作是一个标记出对象的类,例如my。 newString 确实传递函数,可以被视为函数式编程;另一方面,函数式编程通常被认为是无副作用的,my对象可以修改,这比函数式编程更OO。
标签: r