Pergunta

Posso criar um operador de composição em R:

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

Para ser usado assim:

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

mas gostaria de saber se existe um conjunto oficial de funções para fazer esse tipo de coisa e outras operações como curry em R.Em grande parte, isso é para reduzir o número de colchetes, palavras-chave de função, etc. em meu código.

Minha função de curry:

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

Isto é especialmente bom para, por ex.agregar:

> 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

O que considero muito mais elegante e editável do que:

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

Basicamente eu quero saber - isso já foi feito para R?

Foi útil?

Solução

O local padrão para programação funcional em r é agora o functional biblioteca.

Da Biblioteca:

Funcional: curry, composição e outras funções de ordem superior

Exemplo:

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

Cran:https://cran.r-project.org/web/packages/function/index.html

PS: Esta biblioteca substitui o ROxigen biblioteca.

Outras dicas

Ambas as funções realmente existem em a roxygen pacote (Veja o código -fonte aqui) de Peter Danenberg (foi originalmente baseado em Solução de Byron Ellis no 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,
                       ...)
}

Observe o uso do Reduce função, o que pode ser muito útil ao tentar fazer programação funcional em R. Veja? Reduza para obter mais detalhes (que também abrange outras funções, como Map e Filter).

E seu exemplo de curry (ligeiramente diferente neste uso):

> library(roxygen)
> p <- Curry(paste, collapse="")
> p(letters[1:10])
[1] "abcdefghij"

Aqui está um exemplo para mostrar a utilidade de Compose (Aplicando três funções diferentes às cartas):

> Compose(function(x) x[length(x):1], Curry(paste, collapse=""), toupper)(letters)
[1] "ZYXWVUTSRQPONMLKJIHGFEDCBA"

E seu exemplo final funcionaria assim:

> aggregate(df[,"t"], df["l"], Compose(Curry(paste, collapse=""), toupper))
  l    x
1 1  ABG
2 2 DEFH
3 3  CIJ

Por fim, aqui está uma maneira de fazer a mesma coisa com plyr (também poderia ser feito facilmente com by ou aggregate Como já mostrado):

> library(plyr)
> ddply(df, .(l), function(df) paste(toupper(df[,"t"]), collapse=""))
  l   V1
1 1  ABG
2 2 DEFH
3 3  CIJ

Há uma função chamada curry no Roxygen pacote.
Encontrado via esta conversa no arquivo de correio R.

Uma abordagem mais complexa é necessária se você quiser que os 'nomes' das variáveis ​​sejam transmitidos com precisão.

Por exemplo, se você fizer plot(rnorm(1000),rnorm(1000)) então você obterá ótimos rótulos em seus eixos x e y.Outro exemplo disso é 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

Não que o data.frame tenha atribuído nomes úteis às colunas.

Algumas implementações de Curry podem não fazer isso corretamente, levando a nomes de colunas e rótulos de gráficos ilegíveis.Em vez disso, agora uso algo assim:

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())
    }
}

Isso é bastante complexo, mas acho que está correto. match.call irá capturar todos os argumentos, lembrando completamente quais expressões definiram os argumentos (isso é necessário para rótulos legais).O problema é que ele captura muitos argumentos - não apenas os ... mas também o FUN.Ele também lembra o nome da função que está sendo chamada (Curry).

Portanto, queremos excluir essas duas primeiras entradas em .orig para que .orig realmente corresponde apenas ao ... argumentos.É por isso que fazemos .orig[[1]]<-NULL duas vezes - cada vez exclui uma entrada e desloca todo o resto para a esquerda.

Isso completa a definição e agora podemos fazer o seguinte para obter exatamente O mesmo que acima

Curry(data.frame, rnorm(5), rnorm(5) )( first=rpois(5,1) , second=rbinom(5,1,0.5) )

Uma nota final sobre envir=parent.frame().Usei isso para garantir que não haverá problema se você tiver variáveis ​​externas chamadas '.inner' ou '.orig'.Agora, todas as variáveis ​​são avaliadas no local onde o curry é chamado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top