model_macro_builder | R Documentation |
model_macro_builder
takes as input a
function that constructs new lines of model code from the original
line of code. It returns a function suitable for internal use by
nimbleModel
that arranges arguments for input function. Macros
are an experimental feature and are available only after setting
nimbleOptions(enableModelMacros = TRUE)
.EXPERIMENTAL: Turn a function into a model macro builder
A model macro expands one line of code in a nimbleModel into one or
more new lines. This supports compact programming by defining
re-usable modules. model_macro_builder
takes as input a
function that constructs new lines of model code from the original
line of code. It returns a function suitable for internal use by
nimbleModel
that arranges arguments for input function. Macros
are an experimental feature and are available only after setting
nimbleOptions(enableModelMacros = TRUE)
.
model_macro_builder(fun, use3pieces = TRUE, unpackArgs = TRUE)
fun |
A function written to construct new lines of model code. |
use3pieces |
(TRUE or FALSE) Should the arguments from the input
line be split into pieces for the LHS (left-hand side), RHS
(right-hand side, possibly further split depending on
|
unpackArgs |
(TRUE or FALSE) Should arguments be passed as a list (FALSE) or as separate arguments (TRUE)? See details and examples. |
The arguments use3pieces
and unpackArgs
indicate how fun
expects to have arguments arranged from an
input line of code (processed by nimbleModel
).
Consider the defaults use3pieces = TRUE
and unpackArgs =
TRUE
, for a macro called macro1
. In this case, the line of
model code x ~ macro1(arg1 = z[1:10], arg2 = "hello")
will be
passed to fun
as fun(stoch = TRUE, LHS = x, arg1 =
z[1:10], arg2 = "hello")
.
If use3pieces = TRUE
but unpackArgs = FALSE
, then the
RHS will be passed as is, without unpacking its arguments into
separate arguments to fun
. In this case, x ~ macro1(arg1
= z[1:10], arg2 = "hello")
will be passed to fun
as
fun(stoch = TRUE, LHS = x, RHS = macro1(arg1 = z[1:10], arg2 =
"hello"))
.
If use3pieces = FALSE
and unpackArgs = FALSE
, the entire
line of code is passed as a single object. In this case, x ~
macro1(arg1 = z[1:10], arg2 = "hello")
will be passed to fun
as fun(x ~ macro1(arg1 = z[1:10], arg2 = "hello"))
. It is also
possible in this case to pass a macro without using a ~
or
<-
. For example, the line macro1(arg1 = z[1:10], arg2 =
"hello")
will be passed to fun
as fun(macro1(arg1 =
z[1:10], arg2 = "hello"))
.
If use3pieces = FALSE
and unpackArgs = TRUE
, it
won't make sense to anticipate a declaration using ~
or <-
. Ins#' tead, arguments from an arbitrary call will be passed as separate arguments. #' For example, the line macro1(arg1 = z[1:10], arg2 = "hello")
will be pa#' ssed to fun
as fun(arg1 = z[1:10], arg2 = "hello")
.
It is extremely useful to be familiar with processing R code as an
object to write fun
correctly. Functions such as
substitute
and as.name
(e.g. as.name('~')
), quote
, parse
and deparse
are particularly handy.
Multiple lines of new code should be contained in {}
. Extra
curly braces are not a problem. See example 2.
Macro expansion is done recursively: One macro can return code that invokes another macro.
A list with a named element code
that contains the
replacement code.
nimbleOptions(enableModelMacros = TRUE)
nimbleOptions(verbose = FALSE)
## Example 1: Say one is tired of writing "for" loops.
## This macro will generate a "for" loop with dnorm declarations
all_dnorm <- model_macro_builder(
function(stoch, LHS, RHSvar, start, end, sd = 1) {
newCode <- substitute(
for(i in START:END) {
LHS[i] ~ dnorm(RHSvar[i], SD)
},
list(START = start,
END = end,
LHS = LHS,
RHSvar = RHSvar,
SD = sd))
list(code = newCode)
},
use3pieces = TRUE,
unpackArgs = TRUE
)
model1 <- nimbleModel(
nimbleCode(
{
## Create a "for" loop of dnorm declarations by invoking the macro
x ~ all_dnorm(mu, start = 1, end = 10)
}
))
## show code from expansion of macro
model1$getCode()
## The result should be:
## {
## for (i in 1:10) {
## x[i] ~ dnorm(mu[i], 1)
## }
## }
## Example 2: Say one is tired of writing priors.
## This macro will generate a set of priors in one statement
flat_normal_priors <- model_macro_builder(
function(...) {
allVars <- list(...)
priorDeclarations <- lapply(allVars,
function(x)
substitute(VAR ~ dnorm(0, sd = 1000),
list(VAR = x)))
newCode <- quote({})
newCode[2:(length(allVars)+1)] <- priorDeclarations
list(code = newCode)
},
use3pieces = FALSE,
unpackArgs = TRUE
)
model2 <- nimbleModel(
nimbleCode(
{
flat_normal_priors(mu, beta, gamma)
}
))
## show code from expansion of macro
model2$getCode()
## The result should be:
## {
## {
## mu ~ dnorm(0, sd = 1000)
## beta ~ dnorm(0, sd = 1000)
## gamma ~ dnorm(0, sd = 1000)
## }
## }
## Extra curly braces do not matter.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.