Создание реактивной и запоминающейся функции вне яркого контекста - PullRequest
0 голосов
/ 23 января 2019

Я пытаюсь создать «реактивную и запоминающуюся» версию существующей функции, используя функции из shiny - но для использования вне блестящего контекста.

Круто полагаться на shiny::reactive() это то, что

  1. он «автоматически» знает о своих реактивных зависимостях
  2. обрабатывает решение «вернуть кеш или повторно выполнить основное выражение» для нас

Хотя мой подход к передаче тела функции (вместо самой функции ) сам по себе 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

Создано в 2019-01-23 пакетом Представить (v0.2.1)

Подход 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

Создан в 2019-01-23 пакетом Представить (v0.2.1)

Обратите внимание, что при передаче тела от 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

Создано в 2019-01-23 пакетом Представ (v0.2.1)

Странно, попытка использовать missing() и match.arg() в подходе 1 не приводит к ошибкам при запуске кода через reprex::reprex(), но это происходит в интерактивном режиме.

1 Ответ

0 голосов
/ 24 января 2019

Извините, что не совсем разбираюсь в рланге.Но не могли бы вы просто вызвать функцию 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...