2014-06-20 15 views
7

Per alcuni motivi, mi piacerebbe giocare con i richiami R (almeno per quanto riguarda la sintassi) in un modo più Lisp/Scheme (tutti sappiamo che R ha stato heavily inspired by Scheme).Chiamate Lisp/Schema in R

Così, ho creato la seguente funzione:

. <- function(f, ...) 
    eval(match.call()[-1], envir=parent.frame()) 

che mi permette di esprimere per esempio il seguente codice R:

x <- sort(sample(1:10, 5, replace=TRUE)) 
for (i in x) { 
    print(1:i) 
} 

il seguente modulo semanticamente equivalenti:

.(`<-`, x, 
    .(sort, 
     .(sample, 
     .(`:`, 1, 5), 
     5, replace=TRUE))) 

.(`for`, i, x, 
    .(`{`, 
     .(print, 
     .(`:`, 1, i)))) 

Sono abbastanza soddisfatto con l'attuale definizione di . (come è appena fatto per divertimento). Ma è sicuramente tutt'altro che perfetto. In particolare, la sua performance è naturalmente povera:

microbenchmark::microbenchmark(1:10, .(`:`, 1, 10)) 
## Unit: nanoseconds 
##   expr min  lq median uq max neval 
##   1:10 189 212.0 271.5 349 943 100 
## .(`:`, 1, 10) 8809 10134.5 10763.0 11467 44066 100 

Quindi mi chiedo se tu potessi venire con alcune idee relative alla definizione dei . che affrontare la questione di cui sopra. Il codice C/C++ è benvenuto.

+2

Due risorse da considerare che fanno cose correlate: 'do.call' e'%>% 'dal pacchetto' magrittr'. Il primo è simile alla funzione '.' (ma accetta gli argomenti successivi come elenco, non argomenti separati). Quest'ultimo fa molto con la manipolazione delle chiamate per effettuare chiamate di funzioni complete e può avere alcune tecniche per ottenere gli ambienti e l'efficienza giusta. –

+0

@BrianDiggs grazie per il link interessante. Ho visto alcuni voti stretti, quindi ho ristretto la mia domanda solo a problemi di prestazioni. – gagolews

risposta

4

Come commentato in precedenza da Brian Diggs, è possibile utilizzare do.call per eseguire chiamate più veloci senza l'overhead di eval.

> myfn <- function(f, ...) 
+ do.call(f, list(...), envir=parent.frame()) 
> myfn(`:`, 1, 10) 
[1] 1 2 3 4 5 6 7 8 9 10 

> microbenchmark::microbenchmark(1:10, .(`:`, 1, 10), myfn(`:`, 1, 10)) 
Unit: nanoseconds 
      expr min  lq median  uq max neval 
      1:10 177 286.0 346.5 404.0 887 100 
    .(`:`, 1, 10) 9794 11454.0 12141.5 12808.5 48391 100 
myfn(`:`, 1, 10) 3504 4413.5 4751.5 5287.5 48227 100 

Sospetto che per ottenere prestazioni equivalenti a una chiamata di funzione nuda occorrerà modificare la sorgente R stessa.