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))
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)
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)