[R-pkg-devel] Is there a better way ...?
Martin Maechler
m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Thu Oct 21 15:04:22 CEST 2021
>>>>> Duncan Murdoch
>>>>> on Thu, 21 Oct 2021 08:09:02 -0400 writes:
> I agree with almost everything Deepayan said, but would add one thing:
> On 21/10/2021 3:41 a.m., Deepayan Sarkar wrote:
> ...
>> My suggestion is having a package-specific environment, and Duncan's
>> is to have a function-specific environment. If you only need this for
>> this one function, then that should be good enough. If you eventually
>> want to access the persistent information from multiple functions,
>> having a package-specific environment would be more useful.
> I agree with that statement, but those aren't the only two choices.
> Your local() call can create several functions and return them in a
> list; then just those functions have access to the local variables. For
> example,
> createFns <- local({
> .fooInfo <- NULL
> fn1 <- function (...) { ... }
> fn2 <- function (...) { ... }
> list(fn1 = fn1, fn2 = fn2)
> })
> fns <- createFns()
> fn1 <- fns$fn1
> fn2 <- fns$fn2
> Now fn1 and fn2 are functions that can see .fooInfo, and nobody else can
> (without going through contortions).
> One other difference between this approach and the package-specific
> environment: there's only one package-specific environment in
> Deepayan's formulation, but I could call createFns() several times,
> creating several pairs of functions, each pair with its own independent
> version of .fooInfo.
> I don't know if that's something that would be useful to you, but
> conceivably you'd want to maintain partial plots in several different
> windows, and that would allow you to do so.
Note that the above approach has been how nls() has been
implemented for R ... a very long time ago {before R 1.0.0}
e.g. from example(nls) :
DNase1 <- subset(DNase, Run == 1)
fm1 <- nls(density ~ SSlogis(log(conc), Asym, xmid, scal), DNase1)
str(fm1 $ m)
> List of 16
> $ resid :function ()
> $ fitted :function ()
> $ formula :function ()
> $ deviance :function ()
> $ lhs :function ()
> $ gradient :function ()
> $ conv :function ()
> $ incr :function ()
> $ setVarying:function (vary = rep_len(TRUE, np))
> $ setPars :function (newPars)
> $ getPars :function ()
> $ getAllPars:function ()
> $ getEnv :function ()
> $ trace :function ()
> $ Rmat :function ()
> $ predict :function (newdata = list(), qr = FALSE)
> - attr(*, "class")= chr "nlsModel"
## so 16 functions, all sharing the *same* environment very
## efficiently and nicely
## this is *the* environment for the fitted model :
fmE <- environment(fm1$m[[1]])
ls.str(fmE)
> convCrit : function ()
> dev : num 0.00479
> env : <environment: 0x106c88a0>
> form : Class 'formula' language density ~ SSlogis(log(conc), Asym, xmid, scal)
> getPars : function ()
> ....
> ....
> ....
so the environment "contains" the functions themselves (but quite
a few more things) and for an environment that means it only
has pointers to the same function objects which are *also* in `fm1$m`.
So, there has been a nice convincing and important example on
how to do this - inside R for more than two decennia.
Martin Maechler
More information about the R-package-devel
mailing list