【问题标题】:Creating a reactive and memoizable function outside of shiny context在闪亮的上下文之外创建一个反应性和可记忆的函数
【发布时间】:2019-06-16 22:21:23
【问题描述】:

我正在尝试通过利用来自 shiny 的函数来创建现有函数的“反应式和可记忆”版本 - 但用于在闪亮的上下文之外使用。

依赖shiny::reactive() 的好处在于

  1. 它“自动”知道它的反应性依赖关系
  2. 它为我们处理“返回缓存或重新执行底层表达式”的决策

虽然我将函数的body(而不是函数本身)交给shiny::reactive() 的方法本身有效,但它让我放弃了只适用于missing()match.arg() 等函数。

但我似乎无法找到一种方法将函数本身交给shiny::reactive() ,同时仍然使用其内置的缓存/记忆。要看到这一点,请注意foo() 实际上是在每次我们调用foo_react() 时执行的,因此在第二种方法中没有缓存发挥作用

方法 1

# Preliminaries -----
library(shiny)
library(rlang)
options(shiny.suppressMissingContextError=TRUE)
shiny:::setAutoflush(TRUE)

makeReactiveBinding("x_react")
makeReactiveBinding("foo")

# Approach 1: hand foo()'s body to reactive() ----
foo <- function(x_react = get("x_react", 1)) {
  message("Executing foo()")
  x_react * 10
}

expr_inner <- quo(!!fn_body(foo))
expr_react <- quo(reactive({!!expr_inner}))
foo_react <- eval_tidy(expr_react)
print(foo_react)
#> reactive({
#>     ~{
#>         message("Executing foo()")
#>         x_react * 10
#>     }
#> })

x_react <- 1
foo_react() # Executes body of foo()
#> Executing foo()
#> [1] 10
foo_react() # Uses cached result
#> [1] 10
x_react <- 10
foo_react() # Executes body of foo()
#> Executing foo()
#> [1] 100
foo_react() # Uses cached result
#> [1] 100

reprex package (v0.2.1) 于 2019 年 1 月 23 日创建

方法2

# Approach 2: handing foo() itself to reactive() -----
expr_inner <- quo(!!foo)
expr_react <- quo(shiny::reactive({!!expr_inner}))
foo_react <- eval_tidy(expr_react)
print(foo_react)
#> reactive({
#>     ~function (x_react = get("x_react", 1)) 
#>     {
#>         message("Executing foo()")
#>         x_react * 10
#>     }
#> })

x_react <- 1
foo_react()() # Executes foo()
#> Executing foo()
#> [1] 10
foo_react()() # Does NOT use cached result, but executes foo() again
#> Executing foo()
#> [1] 10
x_react <- 10
foo_react()() # Executes foo()
#> Executing foo()
#> [1] 100
foo_react()() # Does NOT use cached result, but executes foo() again
#> Executing foo()
#> [1] 100

reprex package (v0.2.1) 于 2019 年 1 月 23 日创建

请注意,当将foo() 的主体交给reactive() 时,我们将无法使用missing()match.arg() 之类的东西

foo <- function(x_react = get("x_react", 1), y = c("a", "b")) {
  message("Executing foo()")
  try(print(missing(x)))
  try(print(match.arg(y)))
  x_react * 10
}

# Approach 1 -----
expr_inner <- quo(!!fn_body(foo))
expr_react <- quo(reactive({!!expr_inner}))
foo_react <- eval_tidy(expr_react)

x_react <- 1
foo_react() # Executes body of foo()
#> Executing foo()
#> [1] 10

# Approach 2 -----
expr_inner <- quo(!!foo)
expr_react <- quo(shiny::reactive({!!expr_inner}))
foo_react <- eval_tidy(expr_react)

x_react <- 1
foo_react()() # Executes foo()
#> Executing foo()
#> [1] TRUE
#> [1] "a"
#> [1] 10

reprex package (v0.2.1) 于 2019 年 1 月 23 日创建

奇怪的是,在方法 1 中尝试使用 missing()match.arg() 在通过 reprex::reprex() 运行代码时不会导致错误,但在交互模式下会出现错误。

【问题讨论】:

    标签: r shiny memoization reactive


    【解决方案1】:

    抱歉,不太了解 rlang 的内容。但是你能不能只在反应式表达式中调用foo() 函数,如果需要,将它包装在一个函数中传递参数?我尝试像这样调整方法 2:

    library(shiny)
    library(rlang)
    options(shiny.suppressMissingContextError=TRUE)
    shiny:::setAutoflush(TRUE)
    
    makeReactiveBinding("x_react")
    makeReactiveBinding("foo")
    
    foo <- function(x_react = get("x_react", 1), y = c("a", "b")) {
      message("Executing foo()")
      try(print(missing(x_react)))
      try(print(match.arg(y)))
      x_react * 10
    }
    
    foo_react <- function(...) {
      reactive({
        foo(...)
      })
    }
    
    ## no args
    f <- foo_react()
    x_react <- 1
    f()
    # Executing foo()
    # [1] TRUE
    # [1] "a"
    # [1] 10
    f()
    # [1] 10
    
    x_react <- 10
    f()
    # Executing foo()
    # [1] TRUE
    # [1] "a"
    # [1] 100
    f()
    # [1] 100
    
    ## with args
    f <- foo_react(x_react = 3, y = "b")
    f()
    # Executing foo()
    # [1] FALSE
    # [1] "b"
    # [1] 30
    f()
    # [1] 30
    

    【讨论】:

    • 不错!我想这正是我的目标!传递点 - R 的一个很酷的特性,在这种情况下真的很方便。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2021-02-09
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    • 2019-12-05
    相关资源
    最近更新 更多