R purrr 捕获输入和输出

R purrr capture input and outputs

也许这更像是日志记录而不只是函数式编程,但我想知道是否有更 purrr 的方法来实现输入消息和 outputs/diagnostic 消息。

这对我很有用,因为我想在生产中使用 sparklyr 并记录分区查询的作业状态。

library(magrittr)

# Helper to list input params with output
helper = function(x, y, z) {
  c(query = x, params = y, z) 
}

# For single parameters
log_results = function(param, functions, adjective) {

  # Cross the input vectors to apply each function to each parameter set
  crossed_args = purrr::transpose(purrr::cross2(param, functions))
  crossed_params = crossed_args[[1]] %>% unlist
  crossed_function_names = crossed_args[[2]] %>% unlist()

  # Parse to the query to wrap it with quietly
  parsed_functions = purrr::map(crossed_function_names, ~ adjective(eval(parse(text = .x))))

  # Tidy container for function calls
  df = dplyr::data_frame(function_name = crossed_function_names, f = parsed_functions, param = crossed_params)
  # Execute to get query results
  results_log = purrr::map2(df$f, df$param, ~ .x(.y))

  # Output results log as message
  purrr::pmap(.l = list(df$function_name, df$param, results_log), helper) %>% str

}

所有这一切都在做一个 table 的行式作业来调度和返回带有诊断消息的作业。这被转储到日志中,因此如果出现故障,我可以检查哪个作业失败了。

log_results_quietly = purrr::partial(log_results, adjective = purrr::quietly)

> log_results_quietly(c(-1, 3, 4, 5), c("exp", "log"))
List of 8
 $ :List of 6
  ..$ query   : chr "exp"
  ..$ params  : num -1
  ..$ result  : num 0.368
  ..$ output  : chr ""
  ..$ warnings: chr(0) 
  ..$ messages: chr(0) 
 $ :List of 6
  ..$ query   : chr "exp"
  ..$ params  : num 3
  ..$ result  : num 20.1
  ..$ output  : chr ""
  ..$ warnings: chr(0) 
  ..$ messages: chr(0) 
 $ :List of 6
  ..$ query   : chr "exp"
  ..$ params  : num 4
  ..$ result  : num 54.6
  ..$ output  : chr ""
  ..$ warnings: chr(0) 
  ..$ messages: chr(0) 
...

我认为 invoke 可能会有所帮助,但我不能让它与 quietly 一起玩得很好。

如有任何关于如何更好地完成此操作的建议,我们将不胜感激。谢谢

除非我遗漏了什么,否则可以简单地重写为:

cross(list(query = functions, params = param)) %>% 
  map(~ c(.x, adjective(eval(parse(text = .x$query)))(.x$param)))

我不知道为什么你 transpose() cross() 的输出然后 map2() 在它上面,在 [=15= 之后直接 map() 似乎更简单].

此外,您真的希望您的函数仅具有通过 str() 和 return NULL 打印内容的副作用吗? 我建议宁愿 return 你的列表,然后调用 str() 函数的结果。

类似于:

log_results_2 <- function(param, functions, adjective) {
  cross(list(query = functions, params = param)) %>% 
    map(~ c(.x, adjective(eval(parse(text = .x$query)))(.x$param)))
}
log_results_quietly_2 = purrr::partial(log_results_2, adjective = purrr::quietly)
res <- log_results_quietly_2(c(-1, 3, 4, 5), c("exp", "log"))
str(res)

(注意它的顺序与你的不同,因为我先用 functions 调用了 cross()。它可以很容易地调整)

# List of 8
#  $ :List of 6
#   ..$ query   : chr "exp"
#   ..$ params  : num -1
#   ..$ result  : num 0.368
#   ..$ output  : chr ""
#   ..$ warnings: chr(0) 
#   ..$ messages: chr(0) 
#  $ :List of 6
#   ..$ query   : chr "log"
#   ..$ params  : num -1
#   ..$ result  : num NaN
#   ..$ output  : chr ""
#   ..$ warnings: chr "production de NaN"
#   ..$ messages: chr(0) 
#  $ :List of 6
#   ..$ query   : chr "exp"
#   ..$ params  : num 3
#   ..$ result  : num 20.1
#   ..$ output  : chr ""
#   ..$ warnings: chr(0) 
#   ..$ messages: chr(0) 
# ...

此外,我不确定您所说的 "play nice with quietly()" 是什么意思。起初我担心我会遇到懒惰评估的问题,但我没有。

如果您想使用 invoke(),可以将函数中的 map2(df$f, df$param, ~ .x(.y)) 行替换为 invoke_map():

all.equal(
  purrr::map2(df$f, df$param, ~ .x(.y)),
  invoke_map(df$f, df$param)
)
# [1] TRUE