From Robert.McGehee at geodecapital.com  Mon Oct 23 18:06:06 2006
From: Robert.McGehee at geodecapital.com (McGehee, Robert)
Date: Mon, 23 Oct 2006 12:06:06 -0400
Subject: [Rd] Changing function arguments
Message-ID: <67DCA285A2D7754280D3B8E88EB5480211DDA483@MSGBOSCLB2WIN.DMN1.FMR.COM>

Thanks all. Combining your suggestions, and marking up Gabor's example,
below is the function 'chgArg', which recursively goes through an
expression or language object looking for all functions that contain
'arg', and then incrementing that argument by 'offset'. 

The biggest improvement over the suggestions is that chgArg checks the
formals of the function such that if the user does not supply the
argument, but instead relies on the default, the function will still
increment. Also, 'match.call' is used to match the user's expression
with the function call in case one is relying on positional or partial
matching.

ex:
> FUN <- function(xx = 0, yy = 0, zz = 0) xx + yy + zz
> e <- substitute(FUN() + FUN(x = 5)/FUN(xx = 5) + FUN(1, 2, 3))
> chgArg(e, "xx", 1)
[1] FUN(xx = 1) + FUN(xx = 6)/FUN(xx = 6) + FUN(xx = 2, yy = 2, zz = 3)

The only surprise I came across was when I tried explicitly setting
name/value arguments for a call, the name did not "stick", as it would
with a list (though a call object is _clearly_ not a list).

> e <- substitute(FUN(2))
> e[["xx"]] <- 3
> names(e)
[1] NULL

Meaning, I had to explicitly build the call using 'call()'.

Thanks as always for the help,
Robert

chgArg <- function (e, arg, offset) {
    if (is.expression(e)) return(as.expression(Recall(e[[1]], arg = arg,
offset = offset)))
    if (is.symbol(e) || is.double(e)) return (e)
    if (is.function(get(as.character(e[[1]]))) &&
               arg %in% names(formals(as.character(e[[1]])))) {
        mc <- match.call(get(as.character(e[[1]])), e)
        curArg <- ifelse(is.null(mc[[arg]]),
formals(as.character(e[[1]]))[[arg]], mc[[arg]])
        allArgs <- as.list(mc[-1])
        allArgs[[arg]] <- curArg + offset
        e <- do.call("call", c(as.character(mc[[1]]), allArgs))
    }
    for (i in 1:length(e)) e[[i]] <- Recall(e[[i]], arg = arg, offset =
offset)
    return(e)
}

-----Original Message-----
From: Thomas Lumley [mailto:tlumley at u.washington.edu] 
Sent: Monday, October 23, 2006 10:54 AM
To: McGehee, Robert
Cc: R Development Mailing List
Subject: Re: [Rd] Changing function arguments

On Sun, 22 Oct 2006, McGehee, Robert wrote:

> R-Developers,
> I'm looking for some help computing on the R language.
>
> I'm hoping to write a function that parses a language or expression
> object and returns another expression with all instances of certain
> argument of a given function altered. For instance, say I would like
my
> function, myFun to take an expression and whenever the argument 'x'
> appears within the function FUN inside that expression, return an
> altered expression in which 'x' is incremented by one.
>

This sort of recursive parsing and modification is done by the bquote() 
function, so you could look there.

     -thomas

Thomas Lumley			Assoc. Professor, Biostatistics
tlumley at u.washington.edu	University of Washington, Seattle




[Rd] Changing function arguments
McGehee, Robert