R中更高级别的function – 是否有正式的撰写操作员或咖喱function?
我可以在R中创build一个组合操作符:
`%c%` = function(x,y)function(...)x(y(...))
要这样使用:
> numericNull = is.null %c% numeric > numericNull(myVec) [2] TRUE FALSE
但是我想知道是否有一套官方的函数来做这种事情和其他的操作,例如在R中进行。很大程度上是为了减less我的代码中括号,函数关键字等的数量。
我的咖喱function:
> curry=function(...){ z1=z0=substitute(...);z1[1]=call("list"); function(...){do.call(as.character(z0[[1]]), as.list(c(eval(z1),list(...))))}} > p = curry(paste(collapse="")) > p(letters[1:10]) [1] "abcdefghij"
例如聚合这是特别好的:
> df = data.frame(l=sample(1:3,10,rep=TRUE), t=letters[1:10]) > aggregate(df$t,df["l"],curry(paste(collapse="")) %c% toupper) lx 1 1 ADG 2 2 BCH 3 3 EFIJ
我发现它比以下更优雅和可编辑:
> aggregate(df$t, df["l"], function(x)paste(collapse="",toupper(x))) lx 1 1 ADG 2 2 BCH 3 3 EFIJ
基本上我想知道 – 这已经为R完成了吗?
R中函数式编程的标准位置现在是functional
库。
从图书馆:
function:咖喱,撰写和其他更高级的function
例:
library(functional) newfunc <- Curry(oldfunc,x=5)
CRAN: https ://cran.r-project.org/web/packages/functional/index.html
PS:该库替代ROxigen
库。
这两个函数实际上都存在于Peter Danenberg 的roxygen
包 ( 请参阅源代码 )(最初基于Byron Ellis的R-Help解决scheme ):
Curry <- function(FUN,...) { .orig = list(...); function(...) do.call(FUN,c(.orig,list(...))) } Compose <- function(...) { fs <- list(...) function(...) Reduce(function(x, f) f(x), fs, ...) }
请注意Reduce
函数的用法,这在尝试在R中进行函数式编程时非常有用。请参阅Reduce以了解更多详细信息(其中还包括其他函数,如Map
和Filter
)。
而你的咖喱的例子(在这个用法上略有不同):
> library(roxygen) > p <- Curry(paste, collapse="") > p(letters[1:10]) [1] "abcdefghij"
下面是一个例子来展示Compose
的实用性(将三个不同的函数应用于字母):
> Compose(function(x) x[length(x):1], Curry(paste, collapse=""), toupper)(letters) [1] "ZYXWVUTSRQPONMLKJIHGFEDCBA"
而你最后的例子会这样工作:
> aggregate(df[,"t"], df["l"], Compose(Curry(paste, collapse=""), toupper)) lx 1 1 ABG 2 2 DEFH 3 3 CIJ
最后,这里有一个与plyr
做同样的事情的plyr
(也可以很容易地按照已经显示的by
或者aggregate
来完成):
> library(plyr) > ddply(df, .(l), function(df) paste(toupper(df[,"t"]), collapse="")) l V1 1 1 ABG 2 2 DEFH 3 3 CIJ
roxygen软件包中有一个叫Curry的function。
在R邮件存档中通过这个对话find。
如果要让variables的“名称”准确地通过,则需要更复杂的方法。
例如,如果你做plot(rnorm(1000),rnorm(1000))
那么你将在你的x和y轴上得到很好的标签。 另一个例子是data.frame
> data.frame( rnorm(5), rnorm(5), first=rpois(5,1), second=rbinom(5,1,0.5) ) rnorm.5. rnorm.5..1 first second 1 0.1964190 -0.2949770 0 0 2 0.4750665 0.8849750 1 0 3 -0.7829424 0.4174636 2 0 4 1.6551403 1.3547863 0 1 5 1.4044107 -0.4216046 0 0
不是data.frame已经为列指定了有用的名字。
Curry的某些实现可能无法正确执行此操作,导致列名称和标签标签不可读。 相反,我现在使用这样的东西:
Curry <- function(FUN, ...) { .orig = match.call() .orig[[1]] <- NULL # Remove first item, which matches FUN .orig[[1]] <- NULL # Remove another item, which matches Curried argument function(...) { .inner = match.call() .inner[[1]] <- NULL # Remove first item, which matches Curry do.call(FUN, c(.orig, .inner), envir=parent.frame()) } }
这是相当复杂的,但我认为这是正确的。 match.call
将捕获所有的参数,完全记住哪些expression式定义了参数(这是好标签所必需的)。 问题是,它捕捉了太多的参数 – 不仅仅是...
而且还FUN
。 它还记得被调用函数的名字( Curry
)。
因此,我们要删除.orig
前两个条目,这样.orig
实际上只对应于...
参数。 这就是为什么我们做两次.orig[[1]]<-NULL
– 每次删除一个条目并将其他所有内容移到左侧。
这样就完成了定义,现在我们可以做到以上几点
Curry(data.frame, rnorm(5), rnorm(5) )( first=rpois(5,1) , second=rbinom(5,1,0.5) )
关于envir=parent.frame()
最后一个注释。 我使用这个来确保如果你有一个名为'.inner'或'.orig'的外部variables,就不会有问题。 现在,所有variables都在咖喱被调用的地方进行评估。