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以了解更多详细信息(其中还包括其他函数,如MapFilter )。

而你的咖喱的例子(在这个用法上略有不同):

 > 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都在咖喱被调用的地方进行评估。