From charles.dupont at vanderbilt.edu  Thu Mar  9 17:19:53 2006
From: charles.dupont at vanderbilt.edu (Charles Dupont)
Date: Thu, 09 Mar 2006 10:19:53 -0600
Subject: [Rd] Expanding partial names
In-Reply-To: <440E3EE6.4060901@stats.uwo.ca>
References: <440D9295.7090207@stats.uwo.ca>	<eb555e660603071100r57d5f956v453161406fb32c65@mail.gmail.com>	<440E2234.5090406@stats.uwo.ca>
	<440E3EE6.4060901@stats.uwo.ca>
Message-ID: <441055A9.1070203@vanderbilt.edu>

Duncan Murdoch wrote:
> Okay, here's my effort based on Deepayan's and Charles' ideas.  The 
> newArgs function is not what I'd call transparent, but I like the way 
> the wrapper looks.
> 
>  > newArgs <- function(..., Params) {
> +   f <- function(...) list(...)
> +   formals(f) <- c(Params, formals(f))
> 
> +   b <- as.list(body(f))
> +   body(f) <- as.call(c(b[1], names, b[-1]))
> +   f(...)
> + }
>  >
>  > lowlevel <- function(longname = 1) {
> +   cat("longname = ", longname, "\n")
> + }
>  >
>  > newDefaults <- list(longname=2)
>  >
>  > wrapper <- function (...)
> +   do.call("lowlevel", newArgs(..., Params=newDefaults))
> 
> newArgs sets up f to look like
> 
> function (longname = 2, ...) list(longname = longname, ...)
> 
> and then calls it.  The thing I like about this, as opposed to using 
> pmatch, is that I'm sure the partial matching is what's used by R's 
> argument matching, whereas that's only pretty likely with pmatch.
> 
> I also sort of like these lines:
> 
> +   names <- as.list(names(Params))
> +   names(names) <- names
> +   names <- lapply(names, as.name)
> 
> but maybe I should have named Params as names, so they looked like this:
> 
> +   names <- as.list(names(names))
> +   names(names) <- names
> +   names <- lapply(names, as.name)
> 
> And of course I like the fact that this seems to work, but we've seen 
> several versions that do that:
> 
>  > wrapper()
> longname =  2
>  > wrapper(longname=3)
> longname =  3
>  > wrapper(long=3)
> longname =  3
>  > wrapper(long=20)
> longname =  20
>  > wrapper(junk=20)
> Error in lowlevel(longname = 2, junk = 20) :
>          unused argument(s) (junk ...)
> 

If while running the program you don't need to change either the default 
options of the wrapper or the change which lowlevel function is called 
this approach works well if you calculations are not too complicated.

createWrapper <- function(FUN, Params) {
   as.function(c(replace(formals(FUN), names(Params), Params),
                 body(FUN)))
}

const <- 10

newDefaults <- alist(cat = 2,
                      longname = if(cat == 2){
                        if(!missing(dog)) cat + dog
                        else cat + 2
                      } else cat * const, dog=)

wrapper <- createWrapper(lowlevel, newDefaults)

 > wrapper()
longname =  4
 > wrapper(longname=3)
longname =  3
 > wrapper(long=3)
longname =  3
 > wrapper(3)
longname =  3
 > wrapper(cat=4)
longname =  40
 > wrapper(dog=6)
longname =  8
 > wrapper(cat=4, dog=6)
longname =  40
 > wrapper(long=3, cat=4, dog=6)
longname =  3

Charles



[Rd] Expanding partial names
Charles Dupont