2014-06-20 40 views
7

由於某些原因,我希望以更類似Lisp/Scheme的方式使用R調用(至少就語法而言)(我們都知道R有已被heavily inspired by Scheme)。類似於Lisp/Scheme的調用R

因此,我設置了以下功能:

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

,讓我表達如下列R-代碼:

x <- sort(sample(1:10, 5, replace=TRUE)) 
for (i in x) { 
    print(1:i) 
} 
下面的語義等價形式

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

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

我很滿意.當前定義(因爲它只是爲了好玩製造)。但它肯定遠非完美。尤其是它的性能當然是窮人:

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 

所以我想如果你能拿出有關的.的定義,將解決上述問題的一些想法。 C/C++代碼是受歡迎的。

+2

兩個資源可以查看相關內容:'magrittr'包中的'do.call'和'%>%'。前者與'.'函數類似(但將後續參數作爲列表,而不是單獨的參數)。後者通過操縱調用來完成全部的函數調用,並且可能有一些獲取環境和提高效率的技巧。 –

+0

@BrianDiggs感謝有趣的鏈接。我已經看到了一些接近的選票,所以我將我的問題僅限於性能問題。 – gagolews

回答

4

正如Brian Diggs在上面評論的那樣,您可以使用do.call來執行更快速的呼叫,而無需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 

我懷疑獲得與裸函數調用等效的性能將需要修改R源本身。