Fonctions de niveau supérieur dans R - Y a-t-il un opérateur de composition officiel ou une fonction de curry?

StackOverflow https://stackoverflow.com/questions/2228544

Question

Je peux créer un opérateur de composition dans R:

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

À utiliser comme ceci:

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

Mais je voudrais savoir s'il existe un ensemble officiel de fonctions pour faire ce genre de chose et d'autres opérations telles que le curry dans R. Il s'agit en grande partie de réduire le nombre de supports, de mots clés de fonction, etc. dans mon code.

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

C'est particulièrement sympa pour EG agrégé:

> 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

Que je trouve beaucoup plus élégant et modifiable que:

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

Fondamentalement, je veux savoir - cela a-t-il déjà été fait pour R?

Était-ce utile?

La solution

Le lieu standard pour la programmation fonctionnelle dans R est maintenant le functional bibliothèque.

De la bibliothèque:

fonctionnel: curry, composer et autres fonctions d'ordre supérieur

Exemple:

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

CRAN:https://cran.r-project.org/web/packages/fonctional/index.html

PS: cette bibliothèque substitue le ROxigen bibliothèque.

Autres conseils

Ces deux fonctions existent réellement dans la roxygen forfait (Voir le code source ici) de Peter Danenberg (était à l'origine basé sur Solution de Byron Ellis sur 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,
                       ...)
}

Notez l'utilisation du Reduce fonction, qui peut être très utile lorsque vous essayez de faire une programmation fonctionnelle dans R. Voir? Réduisez pour plus de détails (qui couvre également d'autres fonctions telles que Map et Filter).

Et votre exemple de curry (légèrement différent dans cette utilisation):

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

Voici un exemple pour montrer l'utilité de Compose (Application de trois fonctions différentes aux lettres):

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

Et votre dernier exemple fonctionnerait comme ceci:

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

Enfin, voici une façon de faire la même chose avec plyr (pourrait aussi facilement être fait avec by ou aggregate comme déjà montré):

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

Il y a une fonction appelée curry dans le roxygène forfait.
Trouvé via cette conversation sur les archives du courrier R.

Une approche plus complexe est requise si vous souhaitez que les «noms» des variables passent avec précision.

Par exemple, si vous le faites plot(rnorm(1000),rnorm(1000)) Ensuite, vous obtiendrez de belles étiquettes sur vos axes X et Y. Un autre exemple de ceci est 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

Non pas que les données. Frame a attribué des noms utiles aux colonnes.

Certaines implémentations de Curry peuvent ne pas le faire correctement, conduisant à des noms de colonne et à des étiquettes de tracé illisibles. Au lieu de cela, j'utilise maintenant quelque chose comme ceci:

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

C'est assez complexe, mais je pense que c'est correct. match.call Attrapera tous les args, se souvenant pleinement de ce que les expressions ont défini les args (cela est nécessaire pour de belles étiquettes). Le problème est qu'il attrape trop d'args - pas seulement le ... mais aussi le FUN. Il se souvient également du nom de la fonction qui est appelée (Curry).

Par conséquent, nous voulons supprimer ces deux premières entrées dans .orig pour que .orig correspond vraiment au ... arguments. C'est pourquoi nous faisons .orig[[1]]<-NULL Deux fois - à chaque fois, supprime une entrée et déplace tout le reste vers la gauche.

Cela complète la définition et nous pouvons maintenant faire ce qui suit pour obtenir exactement le même que ci-dessus

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

Une dernière note sur envir=parent.frame(). J'ai utilisé cela pour m'assurer qu'il n'y aura pas de problème si vous avez des variables externes appelées «.inner» ou «.orig». Maintenant, toutes les variables sont évaluées à l'endroit où le curry est appelé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top