2828# ' @param object formula object to be updated or evaluated
2929# ' @param newterms a [`term_list`] object, or any list of terms (names
3030# ' or calls) to append to the formula, or a formula whose RHS terms
31- # ' will be used; its `"sign"` attribute vector can give the sign of
32- # ' each term (`+1` or `-1`), and its `"env"` attribute
33- # ' vector will be used to set its environment, with the first
34- # ' available being used and subsequent ones producing a warning.
31+ # ' will be used; it can have a [sign()] method or a `"sign"`
32+ # ' attribute vector can give the sign of each term (`+1` or `-1`),
33+ # ' and its [envir()] method or `"env"` attribute vector will be used
34+ # ' to set its environment, with the first available being used and
35+ # ' subsequent ones producing a warning.
3536# ' @param keep.onesided if the initial formula is one-sided, keep it
3637# ' whether to keep it one-sided or whether to make the initial
3738# ' formula the new LHS
@@ -83,15 +84,15 @@ append_rhs.formula <- function(object = NULL, newterms, keep.onesided = FALSE, e
8384
8485 for (i in seq_along(newterms )){
8586 newterm <- newterms [[i ]]
86- termsign <- if (NVL(attr(newterms , " sign" )[i ], + 1 )> 0 ) " +" else " -"
87+ termsign <- if (NVL(ERRVL2(sign( newterms )[ i ], NULL ), attr(newterms , " sign" )[i ], + 1 )> 0 ) " +" else " -"
8788 if (length(object )== 0 ){
8889 if (termsign == " -" ) newterm <- call(termsign , newterm )
8990 object <- as.formula(call(" ~" , newterm ))
9091 }else if (length(object )== 3 ) object [[3L ]]<- call(termsign ,object [[3L ]],newterm )
9192 else if (keep.onesided ) object [[2L ]]<- call(termsign ,object [[2L ]],newterm )
9293 else object [[3L ]]<- if (termsign == " +" ) newterm else call(termsign ,newterm )
9394
94- NVL(env ) <- termenv <- attr(newterms , " env" )[[i ]]
95+ NVL(env ) <- termenv <- NVL(ERRVL2(envir( newterms ), NULL ), attr(newterms , " env" ) )[[i ]]
9596 if (! is.null(termenv ) && ! identical(env , termenv ))
9697 warning(sQuote(paste0(" newterms[[" ,i ," ]]" )), " has an environment that differs from the specified environment or another term's environment." )
9798 }
@@ -262,15 +263,16 @@ nonsimp.update.formula<-function (object, new, ..., from.new=FALSE){
262263# ' A helper class for list of terms in an formula
263264# '
264265# ' Typically generated by [list_rhs.formula()], it contains, in
265- # ' addition to a list of [call()] or similar objects, attributes
266- # ' `" sign"` and `"env"`, containing, respectively a vector of
267- # ' signs that the terms had in the original formula and a list of
268- # ' environments of the formula from which the term has been
269- # ' extracted. Indexing and concatenation methods preserve these.
266+ # ' addition to a list of [call()] or similar objects information about
267+ # ' the sign of the term and the environment of the formula from which
268+ # ' the term has been extracted, accessible and modifiable via [sign()]
269+ # ' and [envir()] generics. Indexing and concatenation methods preserve
270+ # ' these.
270271# '
271- # ' @param x a list of terms or a term; a `term_list`
272+ # ' @param x,object a list of terms or a term; a `term_list`
272273# ' @param sign a vector specifying the signs associated with each term (`-1` and `+1`)
273274# ' @param env a list specifying the environments, or NULL
275+ # ' @param value RHS; see method documentation
274276# ' @param i list index
275277# ' @param ... additional arguments to methods
276278# '
@@ -289,23 +291,24 @@ nonsimp.update.formula<-function (object, new, ..., from.new=FALSE){
289291# ' (l <- c(l1,l2))
290292# ' \dontshow{
291293# ' stopifnot(identical(c(unclass(l)), alist(b, c, NULL, 1)))
292- # ' stopifnot(identical(attr(l, "sign" ), c(1,1,-1,1 )))
293- # ' stopifnot(identical(attr(l, "env" ), rep(list(e1, globalenv()), each=2)))
294+ # ' stopifnot(identical(sign(l ), c(1L,1L,-1L,1L )))
295+ # ' stopifnot(identical(envir(l ), rep(list(e1, globalenv()), each=2)))
294296# ' }
295297# '
296298# ' (l <- c(l2[1], l1[2], l1[1], l1[1], l2[2]))
299+ # ' sign(l)[3] <- -1L
297300# ' \dontshow{
298301# ' stopifnot(identical(c(unclass(l)), alist(NULL, c, b, b, 1)))
299- # ' stopifnot(identical(attr(l, "sign" ), c(-1,1,1,1,1 )))
300- # ' stopifnot(identical(attr(l, "env" ), list(globalenv(), e1, e1, e1, globalenv())))
302+ # ' stopifnot(identical(sign(l ), c(-1L,1L,-1L,1L,1L )))
303+ # ' stopifnot(identical(envir(l ), list(globalenv(), e1, e1, e1, globalenv())))
301304# ' }
302305# '
303306# ' @export
304- term_list <- function (x , sign = + 1 , env = NULL ){
307+ term_list <- function (x , sign = + 1L , env = NULL ){
305308 if (! is.list(x )) x <- list (x )
306309 if (! is.list(env )) env <- list (env )
307310 structure(x ,
308- sign = rep(sign , length.out = length(x )),
311+ sign = rep(as.integer( sign ) , length.out = length(x )),
309312 env = rep(env , length.out = length(x )),
310313 class = " term_list" )
311314}
@@ -320,38 +323,93 @@ as.term_list.term_list <- function(x, ...) x
320323
321324# ' @rdname term_list
322325# ' @export
323- as.term_list.default <- function (x , sign = + 1 , env = NULL , ... ) term_list(x , sign = sign , env = env )
326+ as.term_list.default <- function (x , sign = + 1L , env = NULL , ... ) term_list(x , sign = sign , env = env )
324327
325328# ' @rdname term_list
326329# ' @export
327330c.term_list <- function (x , ... ){
328331 xl <- c(list (as.term_list(x )), lapply(list (... ), as.term_list ))
329332 structure(
330333 c(unclass(x ), ... ),
331- sign = unlist(lapply(xl , attr , " sign" ), use.names = FALSE ),
332- env = unlist(lapply(xl , attr , " env " ), recursive = FALSE , use.names = FALSE ),
334+ sign = unlist(lapply(xl , sign ), use.names = FALSE ),
335+ env = unlist(lapply(xl , envir ), recursive = FALSE , use.names = FALSE ),
333336 class = " term_list"
334337 )
335338}
336339
337340# ' @rdname term_list
338341# ' @export
339342`[.term_list` <- function (x , i , ... ){
340- term_list(NextMethod(), sign = attr( x , " sign " )[i ], env = attr( x , " env " )[i ])
343+ term_list(NextMethod(), sign = sign( x )[i ], env = envir( x )[i ])
341344}
342345
343346# ' @rdname term_list
344347# ' @export
345348print.term_list <- function (x , ... ){
346- signstr <- ifelse(attr( x , " sign " ) > = 0 , " +" , " -" )
347- envstr <- sapply(attr( x , " env " ), format )
349+ signstr <- ifelse(sign( x ) > = 0L , " +" , " -" )
350+ envstr <- sapply(envir( x ), format )
348351 termstr <- lapply(lapply(x , format ), paste0 , collapse = " \n " )
349352
350353 cat(" Term List:\n " )
351354 cat(paste(signstr , termstr , envstr , collapse = " \n " ))
352355 cat(" \n " )
353356}
354357
358+ # ' @describeIn term_list An [`integer`] vector giving the signs of
359+ # ' each term in the list.
360+ # ' @export
361+ sign.term_list <- function (x ) attr(x , " sign" )
362+
363+ # ' A generic for setting the sign of an object
364+ # '
365+ # ' @param x object whose sign is to be set
366+ # ' @param value a numeric vector specifying the sign
367+ # ' @export
368+ `sign<-` <- function (x , value ) UseMethod(" sign<-" )
369+
370+ # ' @describeIn term_list Update the signs of the terms; `value` is
371+ # ' recycled to the length of the list.
372+ # ' @export
373+ `sign<-.term_list` <- function (x , value ) structure(x , sign = rep_len(as.integer(sign(value )), length(x )))
374+
375+ # ' A generic for querying and setting an object's environment
376+ # '
377+ # ' [environment()] and [environment<-()] are not generics, so it is
378+ # ' not possible to dispatch based on the class of the object affected.
379+ # '
380+ # ' When no method is available, these generics fall back to the
381+ # ' [environment()] and [environment<-()] functions.
382+ # '
383+ # ' @param object object whose environment is to be queried or set
384+ # ' @param value typically an [`environment`], but could be any RHS
385+ # ' supported by the method
386+ # '
387+ # ' @export
388+ `envir` <- function (object ) UseMethod(" envir" )
389+
390+ # ' @noRd
391+ # ' @export
392+ `envir.default` <- function (object ) environment(object )
393+
394+ # ' @rdname envir
395+ # ' @export
396+ `envir<-` <- function (object , value ) UseMethod(" envir<-" )
397+
398+ # ' @noRd
399+ # ' @export
400+ `envir<-.default` <- function (object , value ) `environment<-`(object , value )
401+
402+ # ' @describeIn term_list A [`list`] with an element for each term in
403+ # ' the list, giving its environment.
404+ # ' @export
405+ `envir.term_list` <- function (object ) attr(object , " env" )
406+
407+ # ' @describeIn term_list Update the environments of the terms; `value`
408+ # ' can be an environment or a list of environments, recycled to the
409+ # ' length of the term list.
410+ # ' @export
411+ `envir<-.term_list` <- function (object , value ) structure(object , env = rep_len(enlist(value ), length(object )))
412+
355413.recurse_summation <- function (x , sign ){
356414 if (length(x )== 1 )
357415 term_list(x , sign )
@@ -414,21 +472,21 @@ list_summands.call<-function(object){
414472# '
415473# ' @examples
416474# ' stopifnot(identical(list_rhs.formula(a~b),
417- # ' structure(alist(b), sign=1 , env=list(globalenv()), class="term_list")))
475+ # ' structure(alist(b), sign=1L , env=list(globalenv()), class="term_list")))
418476# ' stopifnot(identical(list_rhs.formula(~b),
419- # ' structure(alist(b), sign=1 , env=list(globalenv()), class="term_list")))
477+ # ' structure(alist(b), sign=1L , env=list(globalenv()), class="term_list")))
420478# ' stopifnot(identical(list_rhs.formula(~b+NULL),
421479# ' structure(alist(b, NULL),
422- # ' sign=c(1,1 ), env=rep(list(globalenv()), 2), class="term_list")))
480+ # ' sign=c(1L,1L ), env=rep(list(globalenv()), 2), class="term_list")))
423481# ' stopifnot(identical(list_rhs.formula(~-b+NULL),
424482# ' structure(alist(b, NULL),
425- # ' sign=c(-1,1 ), env=rep(list(globalenv()), 2), class="term_list")))
483+ # ' sign=c(-1L,1L ), env=rep(list(globalenv()), 2), class="term_list")))
426484# ' stopifnot(identical(list_rhs.formula(~+b-NULL),
427485# ' structure(alist(b, NULL),
428- # ' sign=c(1,-1 ), env=rep(list(globalenv()), 2), class="term_list")))
486+ # ' sign=c(1L,-1L ), env=rep(list(globalenv()), 2), class="term_list")))
429487# ' stopifnot(identical(list_rhs.formula(~+b-(NULL+c)),
430488# ' structure(alist(b, NULL, c),
431- # ' sign=c(1,-1,-1 ), env=rep(list(globalenv()), 3), class="term_list")))
489+ # ' sign=c(1L,-1L,-1L ), env=rep(list(globalenv()), 3), class="term_list")))
432490# '
433491# ' @export
434492list_rhs.formula <- function (object ){
0 commit comments