我可以在R中创建一个撰写操作员:

 `%c%` = function(x,y)function(...)x(y(...)) 

这样使用:

 > numericNull = is.null %c% numeric
 > numericNull(myVec)
 [2] TRUE FALSE

但是我想知道是否有一组正式的功能可以执行此类操作和其他操作,例如在R中进行咖喱。这在很大程度上是为了减少我代码中的括号,功能关键字等的数量。

我的咖喱功能:

> 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"

这对于EG汇总特别好:

> df = data.frame(l=sample(1:3,10,rep=TRUE), t=letters[1:10])
> aggregate(df$t,df["l"],curry(paste(collapse="")) %c% toupper)
  l    x
1 1  ADG
2 2  BCH
3 3 EFIJ

我发现它比以下内容更优雅和可编辑:

> aggregate(df$t, df["l"], function(x)paste(collapse="",toupper(x)))
  l    x
1 1  ADG
2 2  BCH
3 3 EFIJ

基本上我想知道 - 这已经是为R完成的吗?

有帮助吗?

解决方案

R现在在R中的功能编程的标准位置是 functional 图书馆。

从图书馆:

功能:咖喱,组成和其他高阶功能

例子:

   library(functional)
   newfunc <- Curry(oldfunc,x=5)

克兰:https://cran.r-project.org/web/packages/functional/index.html

PS:这个库替换 ROxigen 图书馆。

其他提示

这两个功能实际上都存在于 roxygen 包裹 (在此处查看源代码)来自Peter Danenberg(最初是基于 拜伦·埃利斯(Byron Ellis)在R-Help上的解决方案):

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中进行功能编程时,这可能非常有用。 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))
  l    x
1 1  ABG
2 2 DEFH
3 3  CIJ

最后,这是一种与 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 包裹。
通过 这个对话 在R邮件档案中。

如果您希望变量的“名称”准确地通过,则需要一种更复杂的方法。

例如,如果您这样做 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 <- function(FUN, ...) {
    .orig = match.call()
    .orig[[1]] <- NULL # Remove first item, which matches Curry
    .orig[[1]] <- NULL # Remove another item, which matches FUN
    function(...) {
        .inner = match.call()
        .inner[[1]] <- NULL # Remove first item, which matches Curry
        do.call(FUN, c(.orig, .inner), envir=parent.frame())
    }
}

这很复杂,但我认为这是正确的。 match.call 将捕获所有的args,充分记住哪些表达式定义了args(这对于漂亮的标签是必需的)。问题是它抓住了太多的args-不仅仅是 ... 但也是 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”,则不会出现问题。现在,在调用咖喱的地方评估所有变量。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top