R 在函数中使用eval()时应该调用哪个环境?

R 在函数中使用eval()时应该调用哪个环境?,r,scope,eval,R,Scope,Eval,我有一系列的函数,我正在尝试使用它们,我正在努力找出为什么这个任务不起作用。以下是我正在使用的函数: new_timeline <- function() { timeline = structure(list(), class="timeline") timeline$title <- list("text" = list("headline" = NULL, "text" = NULL), "start_date" =

我有一系列的函数,我正在尝试使用它们,我正在努力找出为什么这个任务不起作用。以下是我正在使用的函数:

new_timeline <- function() {
  timeline = structure(list(), class="timeline")

  timeline$title <- list("text" = list("headline" = NULL, "text" = NULL),
                         "start_date" = list("year" = NULL, "month" = NULL, "day" = NULL),
                         "end_date" = list("year" = NULL, "month" = NULL, "day" = NULL))

  return(timeline)
}

.add_date <- function(self, date, time_type) {
  valid_date <- stringr::str_detect(date, "^[0-9]{4}(-[0-9]{1,2}){0,2}$")
  if (!valid_date) {
    stringr::str_interp("Your ${time_type} date does not appear to be formatted correctly. It must be of the form 'yyyy-mm-dd'. Only the year is required.") %>% stop()
  }

  date_elements <- date %>% as.character() %>% stringr::str_split(" ") %>% unlist()
  date <- date_elements[1] %>% stringr::str_split("-") %>% unlist()
  stringr::str_interp("self$title$${time_type}_date$year <- date[1]") %>% parse(text = .) %>% eval()
  if (!is.na(date[2])) stringr::str_interp("self$title$${time_type}_date$month <- date[2]") %>% parse(text = .) %>% eval()
  if (!is.na(date[3])) stringr::str_interp("self$title$${time_type}_date$day <- date[3]") %>% parse(text = .) %>% eval()

  return(self)
}

edit_title <- function(self, headline = NULL, text = NULL, start_date = NULL, end_date = NULL) {

  if (class(self) != "timeline") stop("The object passed must be a timeline object.")
  if (is.null(headline) && is.null(self$title$text$headline)) stop("Headline cannot be empty when adding a new title.")

  if (!is.null(headline)) self$title$text$headline <- headline
  if (!is.null(text)) self$title$text$text <- text
  if (!is.null(start_date)) self <- .add_date(self, date = start_date, time_type = "start")
  if (!is.null(end_date)) self <- .add_date(self, date = end_date, time_type = "end")

  return(self)
}
new_时间线%unlist()

stringr::str_interp(“self$title$${time\u type}}\u date$year如评论中所述,我认为您可能不需要所有的代码解析,只需在
[[
用于您的作业。无论如何,当您使用管道操作符时,会发生一系列函数换行,因此确定要返回多少帧是一件痛苦的事情。以下是修改
.add\u date
函数的几种解决方案

您已经找到了一个,使用
%
解析(text=)%%>%eval(envir=sys.frame(goback))
##解决方案2:使用函数中定义的环境

如果在运行示例时(!is.na(date[2])stringr::str_interp(“self$title$${time\u type}}\u date$month),则我得到
无法找到函数“edit\u timeline”
@Pascal Good call;这是我的一个输入错误。它已经被更正。哦,伙计,环境与管道操作符变得非常复杂。你有没有可能简化这个示例?快速通读之后,大多数代码看起来都不相关。这是一种奇怪的方式,很难了解发生了什么。我不知道首先,我要理解你为什么要使用
str\u interp
。你可以使用
self$title[[paste0(time\u type),“\u date”]]$month
这样一个简单的解决方案。我不知道为什么我不想使用
[[
…我非常感谢您对环境和框架的解释,并演示了如何调试这些内容,但我最终还是使用了您的简化来修复我的代码。感谢您的帮助!很高兴听到您这样说!这就是正确的方法
library(magrittr)
#devtools::install_github("hadley/stringr")
library(stringr)

tl <- new_timeline()
tl <- tl %>% edit_title(headline = "My Timeline", text = "Example", start_date = "2015-10-18")
.add_date <- function(self, date, time_type) {
    valid_date <- stringr::str_detect(date, "^[0-9]{4}(-[0-9]{1,2}){0,2}$")
    if (!valid_date) {
        stringr::str_interp("Your ${time_type} date does not appear to be formatted correctly. It must be of the form 'yyyy-mm-dd'. Only the year is required.") %>% stop()
    }

    ## Examining environemnts
    e <- environment()                                                              # current env
    efirst <- sys.nframe()                                                          # frame number
    print(paste("Currently in frame", efirst))
    envs <- stringr::str_interp("${date}") %>% parse(text=.) %>% {.; sys.frames()}  # list of frames
    elast <- stringr::str_interp("${date}") %>% parse(text=.) %>% {.; sys.nframe()} # number of last
    print(paste("Went", elast, "frames deep."))

    ## Go back this many frames in eval
    goback <- efirst-elast

    date_elements <- date %>% as.character() %>% stringr::str_split(" ") %>% unlist()
    date <- date_elements[1] %>% stringr::str_split("-") %>% unlist()

    ## Solution 1: use sys.frame
    stringr::str_interp("self$title$${time_type}_date$year <- date[1]") %>%
      parse(text = .) %>% eval(envir=sys.frame(goback)) 

    ## Solution 2: use environment defined in function
    if (!is.na(date[2])) stringr::str_interp("self$title$${time_type}_date$month <- date[2]") %>%
      parse(text = .) %>% eval(envir=e)

    return(self)
}