2010-02-09 5 views
35

Ich kann einen compose Operator in R erstellen:höhere Funktionen in R - gibt es eine offizielle komponieren Operator oder Curry-Funktion?

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

wie folgt zu verwenden:

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

aber ich möchte es wissen, ob ein offizieller Satz von Funktionen ist diese Art von tun Sache und andere Operationen wie Curry in R. Hauptsächlich ist dies die Anzahl der Klammern, Funktion Keywords usw. in meinem Code zu reduzieren.

Meine Curry-Funktion:

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

Dies ist besonders schön für z.B. Aggregat:

> 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 

Was ich als viel eleganter und bearbeitbare finden:

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

Grundsätzlich möchte ich wissen - hat dies bereits für R getan?

+0

Beachten Sie, dass mein Curry-Aufruf derzeit curried Variablen nicht aus der Umgebung bindet, in der es aufgerufen wird, sondern von wo die zurückgegebene Funktion aufgerufen wird. Ich arbeite daran. –

+2

Wenn Sie nur eine Einfügefunktion mit besseren Standardeinstellungen wünschen, warum sollten Sie sich mit dem Curry-Verfahren beschäftigen? Einfach definieren, z.B. 'paste0 <- function (x, ...) einfügen (toupper (x), collapse =" ", ...)' Dann kann man 'aggregate (df $ t, df [" l "], paste0)' nennen –

+4

weil es komplexer wird, wenn Sie mehr Funktionen stapeln möchten. –

Antwort

5

Der Standardplatz für die funktionale Programmierung in R ist jetzt die Bibliothek functional.

Aus der Bibliothek:

funktional: Curry, Compose und andere Funktionen höherer Ordnung

Beispiel:

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

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

PS : Dieser Bibliotheksersatz utes die ROxigen Bibliothek.

2

Es gibt eine Funktion namens Curry im roxygen Paket.
Gefunden über this conversation auf dem R-Mail-Archiv.

+0

Leider funktioniert der Link nicht. Es ist wahrscheinlich das: https://stat.ethz.ch/pipermail/r-help/2009-December/221224.html –

+0

@FlorianJenn Danke; Ich habe den Link in der Antwort aktualisiert. –

28

Beide Funktionen existieren tatsächlich in the roxygen package (see the source code here) von Peter Danenberg (basierte ursprünglich auf Byron Ellis's solution on 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, 
         ...) 
} 

Beachten Sie die Verwendung der Reduce Funktion, die sehr hilfreich sein kann, wenn sie versuchen zu tun Funktionale Programmierung in R. Siehe? Reduce für weitere Details (die auch andere Funktionen wie Map und Filter umfasst).

Und Ihr Beispiel Curry (etwas anders in dieser Nutzung):

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

Hier ist ein Beispiel für die Nützlichkeit von Compose zu zeigen (die Anwendung drei verschiedene Funktionen Buchstaben):

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

Und Ihr letztes Beispiel würde folgendermaßen aussehen:

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

Schließlich, hier ist ein Weg, um die gleiche Sache mit plyr (könnte auch leicht mit by oder aggregate wie bereits gezeigt durchgeführt werden) zu tun:

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

Gibt es nicht etwas Falsches an der Verwendung eines Pakets für literarische Programmierung für die funktionale Programmierung? Was sagt das über die Modularität von R-Bibliotheken aus? – piccolbo

+9

FWIW, 'Compose' und' Curry' wurden vor einiger Zeit in das 'funktionale' Paket verschoben. –

2

Ein komplexerer Ansatz ist erforderlich, wenn Sie die ‚Namen‘ der Variablen wollen genau passieren.

Zum Beispiel, wenn Sie plot(rnorm(1000),rnorm(1000)) tun, dann erhalten Sie schöne Etiketten auf Ihrer X-und Y-Achsen. Ein weiteres Beispiel dafür ist 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 

Nicht, dass die data.frame nützliche Namen zu den Spalten zugewiesen hat.

Einige Implementierungen von Curry funktionieren möglicherweise nicht richtig, was zu unlesbaren Spaltennamen und Plot-Labels führt. Stattdessen benutze ich jetzt etwas wie folgt:

Das ist ziemlich komplex, aber ich denke, es ist richtig. match.call fängt alle Argumente ein und merkt sich vollständig, welche Ausdrücke die Argumente definiert haben (dies ist für schöne Etiketten notwendig). Das Problem ist, dass es zu viele Argumente fängt - nicht nur die ..., sondern auch die FUN. Es merkt sich auch den Namen der Funktion, die aufgerufen wird (Curry).

Deshalb wollen wir diese ersten beiden Einträge in .orig so löschen, dass .orig wirklich nur auf die ... Argumente entspricht. Deshalb machen wir .orig[[1]]<-NULL zweimal - jedes Mal löscht einen Eintrag und verschiebt alles andere nach links.

Damit ist die Definition und wir können nun folgendes zu bekommen genau die gleichen wie oben

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

Eine letzte Anmerkung auf envir=parent.frame() tun. Ich habe dies verwendet, um sicherzustellen, dass es kein Problem gibt, wenn Sie externe Variablen namens '.inner' oder '.orig' haben. Jetzt werden alle Variablen an der Stelle ausgewertet, an der der Curry aufgerufen wird.

+0

(Beantworter hier) Ich habe das gerade heute erfunden. Ich nehme an, es wurde schon gemacht? Und vielleicht gibt es einen Fehler, von dem ich nichts weiß ?! –