2013-05-01 42 views
9

我試過的功能實現let具有以下語義時叫錯環境:match.call eval'ing

> let(x = 1, y = 2, x + y) 
[1] 3 

...這是概念上有點類似substitutewith語法。

下面的代碼幾乎工作(例如上述調用作品):

let <- function (...) { 
    args <- match.call(expand.dots = FALSE)$`...` 
    expr <- args[[length(args)]] 
    eval(expr, 
     list2env(lapply(args[-length(args)], eval), parent = parent.frame())) 
} 

注嵌套eval,外來評價實際的表達和內評估的參數。

不幸的是,後一種評估發生在錯誤的背景下。這已成爲試圖調用let與檢查當前幀中的功能時,如match.call明顯:

> (function() let(x = match.call(), x))() 
Error in match.call() : 
    unable to find a closure from within which 'match.call' was called 

我想提供父框架爲eval的評價環境中,但是,這並不工作:

let <- function (...) { 
    args <- match.call(expand.dots = FALSE)$`...` 
    expr <- args[[length(args)]] 
    parent <- parent.frame() 
    eval(expr, 
     list2env(lapply(args[-length(args)], function(x) eval(x, parent)), 
        parent = parent) 
} 

這會產生相同的錯誤。這導致我的問題:match.call究竟如何評估?爲什麼這不起作用?而且,我該如何做這項工作?

+0

可能與此相關的是,從'?match.call':「在函數外部調用'match.call'而不指定'定義'是錯誤。然後嘗試'j < - function(x)x; j(match.call())'看到一個錯誤發生的地方。我沒有把這一切都搞清楚了(並沒有完全弄清楚你真的想做什麼),但是這可能是一個錯誤,它與你使用'match.call()'的奇怪方式非常相似。呼叫一個匿名函數。 – 2013-05-01 14:28:36

+0

@Josh我不認爲它是相關的。錯誤信息是不同的,我稱之爲'match.call'的上下文肯定來自函數中,如果錯誤的話。 – 2013-05-01 14:30:27

+0

我想我暗示的是'match.call()'具有非常獨特的範圍規則,它在C級別變爲特殊的硬連線。 (定義'do_matchcall'的代碼,包括一些有關如何調用它的函數的有趣評論,在'$ R_SRC/src/main/unique.c'中。)與幾乎任何其他函數不同,我不清楚它的評估環境可以通過調用'eval()'來操縱/設置。爲了簡化你的問題,也許首先要弄清楚爲什麼這不起作用(以及如何實現):'j < - function()eval(call(「match.call」)); Ĵ()'。 – 2013-05-01 15:56:21

回答

6

這個重寫能解決你的問題嗎?

let <- function (expr, ...) { 
    expr <- match.call(expand.dots = FALSE)$expr 
    given <- list(...) 
    eval(expr, list2env(given, parent = parent.frame())) 
} 

let(x = 1, y = 2, x + y) 
# [1] 3 
+0

+1 - 有趣的是'match.call(expand.dots = FALSE)$「...」'和'list(...)'返回不同的對象。 – 2013-05-01 17:21:29

+0

參數在這裏的順序是錯誤的,但這似乎工作。你能解釋**爲什麼**這個工程?即爲什麼我們可以將表達式作爲* last *參數傳遞並仍然將其綁定到第一個?也就是說,這個表達式作爲我的第一個方法存在第一個問題,因爲它不捕獲父範圍......您需要顯式傳遞「parent = parent」。儘管這是參數的默認值,否則這將不起作用:'(function(x)let(y = 2,x + y))(1)' – 2013-05-01 17:57:40

+2

@KonradRudolph - 這只是一個結果或[R的規則/匹配參數的算法](http://stat.ethz.ch/R-manual/R-devel/doc/manual/R-lang.html#Argument-matching)。首先處理已命名的參數(這裏'x = 1'和'y = 2'),並且它們都沒有與單個命名形式('expr')匹配的名稱。然後,如上面鏈接所述「任何不匹配的形式參數都必須按照未命名的參數進行排序」。這意味着'x + y'被綁定到'expr'。 – 2013-05-01 18:09:39