2014-06-20 15 views
7

Z pewnych powodów chciałbym grać z R (przynajmniej jeśli chodzi o składnię) w sposób bardziej Lisp/Scheme (wszyscy wiemy, że R ma był heavily inspired by Scheme).Lisp/Połączenia podobne do schematów w R

Zatem skonfigurować następującą funkcję:

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

który pozwala mi wyrazić np następujący kod R:

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

w następującym semantycznie równoważne formie:

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

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

Jestem całkiem zadowolony z obecnej definicji . (jak to właśnie wykonanego dla zabawy). Ale na pewno nie jest to doskonałe. W szczególności jego wydajność jest oczywiście złym:

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 

Więc zastanawiam się, czy można wymyślić kilka pomysłów dotyczących definicji ., który zajmowałby się powyższą kwestię. C/C++ jest mile widziany.

+2

Dwa zasoby do obejrzenia tego powodują powiązane rzeczy: 'do.call' i'%>% 'z pakietu' magrittr'. Pierwsza jest podobna do twojej funkcji '.' (ale przyjmuje kolejne argumenty jako listę, a nie oddzielne argumenty). Ta ostatnia robi wiele z manipulacją wywołań, aby wykonać pełne wywołania funkcji i może mieć pewne techniki pozwalające uzyskać odpowiednie środowisko i wydajność. –

+0

@BrianDiggs dzięki za interesujący link. Widziałem kilka głosów, więc zawęziłem moje pytanie tylko do kwestii wydajności. – gagolews

Odpowiedz

4

Jak zauważył powyżej Brian Diggs, można użyć numeru do.call, aby wykonywać szybsze połączenia bez kosztów ogólnych 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 

Podejrzewam, że uzyskanie równoważnej wydajności dla niejawnego wywołania funkcji będzie wymagać modyfikacji samego źródła R.

Powiązane problemy