繁体   English   中英

如何在R中实现块作用域?

[英]How to achieve block scoping in R?

我正在考虑在R中实现块作用域的方法。这对于在数据科学笔记本/交互式会话中保持干净的工作空间非常有用。 目前,我正在使用这样的IIFE模式

(function(){
temp1 <- ...
temp2 <- ...
temp3 <- ...

data <<- fn(temp1, temp2, temp3)
})()

这样,我可以创建/更新数据,并让临时文件在我之后被清理。 显然,它在潜在地分配给全局方面仍然有副作用,但是对于数据分析而不是我不关心的软件包。

直到IIFE在RI中变得更流行之前,为此才想到有一个特殊的运算符会很巧妙,但是我对R元编程的了解还不够。 在我幼稚的头脑中,以下内容就足够了

`%gets%` <- function(x, val) {
    val <- local(val)
    assign(deparse(substitute(x)), val, envir = parent.frame())
}

x1 %gets% {
    x = 10;
    x + 5
}

但是x仍然被丢弃到我的全局范围内。 所以

  1. 这是模拟块作用域的合理实现吗?
  2. 如果是这样,如何防止我的x转义到外部范围?

1)local首先注意,这有效:

if (exists("x")) rm(x) # just for reproducibility.  Don't need this normally.
x1 <- local({ x <- 10; x + 5})

x1
## [1] 15

x
## Error: object 'x' not found

2)%gets%要实现%gets%我们可以使用如下所示的substitute

`%gets%` <- function(.x, .value) {
  assign(deparse(substitute(.x)), eval.parent(substitute(local(.value))), parent.frame())
}

x1 %gets% {
    x = 10;
    x + 5
}

x1
## [1] 15

x
## Error: object 'x' not found

2a):=我们可以通过定义:=来使它变得更好:

`:=` <- `%gets%`

# test
x1 := { x <- 10; x + 5}

x1
## [1] 15

x
## Error: object 'x' not found

3)管道也可以使用管道来避免整体。 在此,管道完成后xy不会持续存在。

library(magrittr)

list(x = 6) %$% { y <- 1; x + y + 5 }
## [1] 12

x
## Error: object 'x' not found

y
## Error: object 'y' not found

或如果我们没有什么可以通过的:

x1 <- list() %>% { x <- 10; x + 5 }

x1
## [1] 15

x
## Error: object 'x' not found

或者我们可以使用0保存击键:

x1 <- 0 %>% { x <- 10; x + 5 }

更新已修订(2)以简化和纠正它。 还添加了(2a)和(3)。

local可以满足您的要求 (并且IIFE是JavaScript的一种变种,可以解决缺乏类似于local的功能的问题)。

您的%gets%代码失败,因为您误解了如何评估参数:在函数中, val是一个参数。 这意味着它将在调用方的范围内进行评估 ,没有例外。 将其包装在local只是意味着将val的评估结果包装在local中,即在这种情况下没有意义。 并不意味着该表达式为本地计算; 如果是这种情况,则完全不需要local ,可以在函数的作用域中对其进行评估。

可以根据需要使用eval 做到这一点:

`%gets%` = function (x, expr) {
    assign(
        as.character(substitute(x)),
        eval(substitute(expr)),
        parent.frame()
    )
}

…但这不是很有用,因为它无法访问调用者作用域的变量; 相反,您必须在注入调用者范围的范围内对其进行评估,以便您拥有一个“干净”的环境,但仍可以访问现有变量:

`%gets%` = function (x, expr) {
    parent = parent.frame()
    assign(
        as.character(substitute(x)),
        eval.parent(substitute(eval(quote(expr), new.env(parent = parent)))),
        parent
    )
}

…但这本质上只是重新定义local分配的一种复杂方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM