Захват функций с помощью enxprs rlang

Я пишу такую ​​функцию, что вызывающие ее функции могут писать схемы декларативно:

myschema <- Schema(
  patientID = character,
  temp = numeric,
  treated = logical,
  reason_treated = factor(levels=c('fever', 'chills', 'nausea'))
)

Позже я смогу собрать фреймы данных, используя типы, объявленные в этой схеме. Я думаю, что лучшим кандидатом для этой работы является использование функций метапрограммирования, доступных в rlang:

Schema = function(...) {
  schematypes = rlang::enexprs(...)

}

Однако большинство примеров относится к захвату выражения и последующему их использованию в качестве аргументов функций, а не самих функций. То есть мне трудно уловить правую часть следующего выражения:

patientID = character

а затем позже в состоянии оценить его позже как character(myvec)всякий раз, когда я получаю myvec, То же самое относится к следующему:

reason_treated = factor(levels=c('fever', 'chills', 'nausea'))

который я позже хотел бы оценить как factor(myvec, levels=c('fever', 'chills', 'nausea'))

Спасибо!

1 ответ

Если я правильно понимаю, вы эффективно строите схему из функций и хотите применить эти функции к некоторым аргументам, когда они станут доступны. Это подпадает под зонтик функционального программирования, а не rlang метапрограммированием.

Большая часть нужной вам функциональности уже захвачена purrr::map и его "двигатель" as_mapper, Вы можете использовать его напрямую, чтобы определить

Schema <- function(...) { purrr::map( list(...), purrr::as_mapper ) }

Теперь вы можете использовать его для создания новых схем, как вы предлагали (с небольшими изменениями в определениях функций):

myschema <- Schema(
  patientID = as.character,   # Note the correct function name
  temp = as.numeric,          # Ditto
  treated = as.logical,       # Tritto
  reason_treated = ~factor(., levels=c('fever', 'chills', 'nausea'))
)
# $patientID
# function (x, ...) 
# as.character(x = x, ...)
# <environment: base>
#
# $temp
# function (x, ...) 
# as.double(x = x, ...)
# <environment: base>
#
# $treated
# function (x, ...) 
# as.logical(x = x, ...)
# <environment: base>
# 
# $reason_treated
# function (..., .x = ..1, .y = ..2, . = ..1) 
# factor(., levels = c("fever", "chills", "nausea"))
# <bytecode: 0x00000000027a2d00>

Учитывая вашу новую схему, регистрация новых пациентов может быть выполнена с использованием сестринской функции map это выстраивает аргументы из двух списков / векторов:

register_patient <- function(myvec) { purrr::map2( myschema, myvec, ~.x(.y) ) }
JohnDoe <- register_patient( c(1234, 100, TRUE, "fever") )    
# $patientID
# [1] "1234"
# 
# $temp
# [1] 100
# 
# $treated
# [1] TRUE
# 
# $reason_treated
# [1] fever
# Levels: fever chills nausea

Давайте проверим тип каждого элемента:

purrr::map( JohnDoe, class )
# $patientID
# [1] "character"
# 
# $temp
# [1] "numeric"
# 
# $treated
# [1] "logical"
# 
# $reason_treated
# [1] "factor"
Другие вопросы по тегам