Rudolfs Kregers
Rudolfs Kregers

Reputation: 9

How to Convert a List of Unevaluated Expressions into a List of Expression Objects in R

I am working on a problem in R where I need to convert a list of unevaluated expressions into a format where each element is explicitly wrapped within an expression() object. The expressions involve variables that are not yet defined in the environment. Here are the details of the formats involved:

Input format: my_list <- list(A = a + b, B = b^2)

Desired output format: list(A = expression(a + b), B = expression(b^2))

The key challenge is that the variables a and b are not defined when the list is created, and I want to avoid any evaluation of these expressions during the conversion. The conversion must handle the expressions such that they are ready for later evaluation, while remaining unevaluated in their new form.

There is requirment that we cannot use the dots (...) as the input is only a single unevalauted list object.

I tried finding a solution in Hadley's book "Advanced R", but there was no information on how we could take an unevaluated object and convert it to subexpressions (there were some clever tricks with dots, but we have the restriction that all the calls be already packed into the list class object).

I also tried ChatGPT, which gave me confidence that we are still very far from when AI will completely take over our jobs.

Upvotes: 1

Views: 87

Answers (3)

Konrad Rudolph
Konrad Rudolph

Reputation: 545588

Your requirements are a tad vague but based on your attempted solution I think you need the following:

expression2listed_expressions = function (expr_list) {
  expr_list = substitute(expr_list)
  expr_list[[1L]] = quote(alist)
  eval(expr_list)
}

Basically: use alist() instead of list(); and if you can’t control how the function is called then you can take the unevaluated input and replace list() with alist() in the syntax tree.

Alternatively you can omit the evaluation altogether: substitute() already makes your input unevaluated — you only need to extract it from the list() call node in the syntax tree (the as.list() converts the sub-expression from a call into a regular list):

expression2listed_expressions = function (expr_list) {
  expr_list = substitute(expr_list)
  as.list(expr_list)[-1L]
}

Note that this doesn’t return a list of expression objects. You can trivially wrap the result into expression objects, but this is probably unnecessary.

Upvotes: 0

Rudolfs Kregers
Rudolfs Kregers

Reputation: 9

Via the use of the frustrating regexpr, I managed to find the solution. It is not the most elegant but at least it works now.

expression2listed_expressions <- function(expr_list) {
  
  # converting the call to string
  expr_string <- rlang::as_label(rlang::enquo(expr_list))
  
  # Strip the 'list(' prefix and the closing ')'
  cleaned_string <- gsub("^\\s*list\\s*\\(|\\s*\\)\\s*$", "", expr_string, perl = TRUE)
  
  # Split the string into separate assignments
  assignments <- strsplit(cleaned_string, ",\\s*(?=[A-Z]\\s*=)", perl = TRUE)[[1]]
  
  result_list <- setNames(lapply(assignments, function(assignment) {
    parts <- strsplit(assignment, "\\s*=\\s*", perl = TRUE)[[1]]  
    name <- parts[1]
    expr <- parts[2]
    (parse(text = expr))
  }), sapply(assignments, function(assignment) {
    strsplit(assignment, "\\s*=\\s*", perl = TRUE)[[1]][1]
  }))
  
  return(result_list)
}

res <- expression2listed_expressions(list(A=a+b, B = b^2, C = mean(c(a, b))))

a <- 1
b <- 2
eval(res$A)
eval(res$B)
eval(res$C)


a <- 5
b <- 25
eval(res$A)
eval(res$B)
eval(res$C)

Upvotes: -2

Carl Witthoft
Carl Witthoft

Reputation: 21502

What source of "user input" ? Your example will not be accepted in the first place. Perhaps require your users to write

 my_input <- c('a+b',  ''b^2')
my_list <- list(A = expression(my_input[1], B = expression(my_input[2]))

Upvotes: 0

Related Questions