Reputation: 5983
I read many articles about R
promises
(including this) and still don't get it.
See code:
library(future)
library(promises)
plan(multiprocess)
read.csv.async <- function(file, header = TRUE, stringsAsFactors = FALSE) {
future({
read.csv(file, header = header, stringsAsFactors = stringsAsFactors)
})
}
df_promise <- read.csv.async("https://rstudio.github.io/promises/data.csv")
df_promise %...>% filter(state == "NY")
df_filtered_promise <- df_promise %...>% filter(state == "NY")
df_filtered_promise
class(df_filtered_promise)
Output:
> read.csv.async <- function(file, header = TRUE, stringsAsFactors = FALSE) {
+ future({
+ read.csv(file, header = header, stringsAsFactors = stringsAsFactors)
+ })
+ }
>
> df_promise <- read.csv.async("https://rstudio.github.io/promises/data.csv")
>
> df_promise %...>% filter(state == "NY")
>
> df_filtered_promise <- df_promise %...>% filter(state == "NY")
>
> df_filtered_promise
<Promise [pending]>
> df_filtered_promise
<Promise [fulfilled: data.frame]>
> class(df_filtered_promise)
[1] "promise"
Why fullfilled promise
doesn't return its value? How can I extract data frame in my case?
Upvotes: 6
Views: 1794
Reputation: 219
promise %>%
{.$then} %>%
environment %>%
{.$private$value}
You can try this.
If promise
is not fullfilled, this will return NULL
.
e.g.
seq(3) %>% promises::promise_map(\ (a) a+1) -> promise
(\ (promise) promise %>%
{.$then} %>% environment %>%
{while (.$private$state != "fulfilled") {
message (.$private$state," ..."); Sys.sleep(1)
}; .$private$value} %>%
{.}) (promise)
If you submit these code to console once, it will prnding ...
forever; but if you submit these code one by one, it will return the result. So if you want to get the result out of the promise
box in a script, you will fail.
So how can we use the value inside that promise
box ? The answer (may be only one) is use then
or %...>%
pipe. And if you have many value in several promise
box, you can do something like this:
seq(3) %>% promises::promise_map(\ (a) a+1) -> promise0
seq(1) %>% promises::promise_map(\ (a) a+1) -> promise1
promise0 %>%
promises::then (\ (a) promise1 %>%
promises::then (\ (b) (a %>% unlist) - (b %>% unlist))) %>%
promises::then (\ (x) x %T>% print %>% class %>% print)
Or clearly, use promise_all
:
seq(3) %>% promises::promise_map (\ (a) a+1) -> promise0
seq(1) %>% promises::promise_map (\ (a) a+1) -> promise1
promise_ab = promises::promise_all (a = promise0, b = promise1)
promise_ab %>%
promises::then (\ (x) (x$a %>% unlist) - (x$b %>% unlist)) %>%
promises::then (\ (x) x %T>% print %>% class %>% print)
(For me, I like the future more ... )
Upvotes: 1
Reputation: 51
df <- environment (promise_object[["then"]])[["private"]][["value"]] is what you are looking for.
Promise object stores data and properties in a nested list format and that list is part of the environment object.
Upvotes: 5
Reputation: 8061
There is a way to do this, but before I tell you, I would advise you not to use promises for interactive or scripting use, probably. Synchronous programming is more convenient than asynchronous, and you should only do the latter if it's very important not to tie up the main R thread (as is the case with Shiny if you want to keep apps responsive while long operations run).
If you choose to use future, try to get away with not chaining any %...>%
operations after it, and then you can simply use future::value
as Daniel Fischer said.
If you do decide to fully use promises, and it's important to you to extract the value out into a regular variable, then you can accomplish this via side effects, like this super-assign:
df_filtered <- NULL
df_filtered_promise %...>% { df_filtered <<- . }
This will cause the df_filtered
variable to be set to the result of df_filtered_promise
at some point in the future. (It will never be assigned in the case of error, though.)
This generally ought not be done in Shiny, as you usually want to keep things wrapped in promises all the way to the end of the computation so Shiny can keep track of what outputs/observers are waiting on what operations.
Upvotes: 9