How to turn a `list()` into a `...` as function parameter

Hi,

I have a very generic question: How do I manipulate a list() into something that can be used in a function that takes only dynamic dots (...) and turns them into a list again?

I would like to feed a list of pointblank agents (a column in a tibble) to pointblank::create_multiagent() which takes several agent objects as parameter ..., then turns the ... into a list.

Salient code:

create_multiagent <- function(
    ...,
    lang = NULL,
    locale = NULL
) {
  
  agent_list <- list(...)

My input data is already a list. In my case, the list contains pointblank agent objects, which themselves are lists (of S3 class "ptblank_agent").

For simplicity, I have dplyr::pulled the agents into a list agents.

> class(agents)
[1] "list"
> agents[[1]]
> class(agents[[1]])
[1] "has_intel"     "ptblank_agent"

I've tried so far:

  • unlist(agents): Disintegrates the agents themselves. With and without recursive=T/F.
  • !!!agents: Error in !agents : invalid argument type.
  • rlang::!!!(agents): ! !!! can only be used within dynamic dots.
  • rlang::flatten(agents) doesn't seem to change agents
  • Web search, SO search, even GPT-4o (hilariously useless)

Short of re-implementing the function in my own package, is there an approach to reverse the list(...)operation?

Edit: Have asked the question at the pointblank repo: Could create_multiagent accept a list of agents? · Issue #552 · rstudio/pointblank (github.com)

I may be completely misunderstanding what you're trying to do, but if I had a function that takes only dynamic dots as an argument, and I wanted to get a variable that is the same as the list I provided, I might do this with relist():

listfun <- function (...) {
  # result <- list(...)
  result <- relist(unlist(list(...)), list(...))[[1]] 
  return(result)
}

l = list(a = 1, b = 2, c = 3)

identical(l, listfun(l))
1 Like

Thanks for the quick answer!

I checked this with my list of objects but I can't seem to get it to work.

# csv_info$agent is the column containing six pointblank agents

args <- relist(unlist(csv_info$agent), csv_info$agent)[[1]] 
# args is a 111.8 MB list of 1315969 elements

ma <- pointblank::create_multiagent(args) # This doesn't work

ma <- pointblank::create_multiagent(
  csv_info$agent[[1]], 
  csv_info$agent[[2]], 
  csv_info$agent[[3]]
) # this works but doesn't scale

So instead of having to type out the elements of my list one by one to create_multiagent (which doesn't scale to an arbitrary number of elements), I would like to supply the entire list programmatically.

So what I want is

my_list <- list(a,b,c)

the_function <- function(...){
 internal_list <- list(...)
 internal_list
}

# Prepare my_list to be used as function argument
my_list_as_dots <- UNKNOWN_FUNCTION(my_list)

the_function(my_list_as_dots) == my_list

As a patch, I've re-implemented (well, copy-pasted) create_multiagent with the only change that I am taking an actual list and not turning dynamic dots into a list. This works like a charm but it feels like a code smell.

create_multiagent_ruPeopleWA <- function(
    agent_list, # Changed: instead of dynamix dots "..."
    lang = NULL,
    locale = NULL
) {

 # Deleted: agent_list <- list(...)

  if (!all(sapply(agent_list, is_ptblank_agent))) {
    rlang::abort("All components of `...` must be an agent")
  }
  agent_list <- rehash_agent_list(agent_list)

Have you tried something like this? (Following example from Injecting with !!, !!!, and glue syntax — topic-inject • rlang)

create_multiagent2 <- function(...) {
  do.call("create_multiagent", list2(...))
}

so that if my_agent_list is your list of agents, you can run:

create_multiagent2(!!!my_agent_list)
1 Like

Thanks @dromano!

This works - much appreciated!

I've learnt something about list2 and !!! today and will take some time to digest the linked article.

Summarising working code from this thread and Could create_multiagent accept a list of agents? · Issue #552 · rstudio/pointblank · GitHub

# agent_list is a programmatically generated tibble column
# make_csv_agent returns a pointblank agent
csv_info <- file_info |>
  dplyr::filter(extension == "csv") |>
  dplyr::rowwise() |>
  dplyr::mutate(
    agent = list(make_csv_agent(filepath) |>  pointblank::interrogate())
  )

# csv_info$agent is identical to a list() of agents
agent_list <- list(agent1, agent2, agent3)

# Option 1
rlang::inject( create_multiagent2(!!!agent_list))

# Option 2
do.call(create_multiagent, agent_list)

# Option 3
create_multiagent2 <- function(...) { do.call("create_multiagent", rlang::list2(...))}
create_multiagent2(!!!my_agent_list)
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.