Hi I want a function that takes precisely one named argument and no unnamed arguments. The named argument must be one of "a" or "b". If "a" is supplied, return "a". If "b" is supplied, return 2*b. That is, the desired behaviour is: R> f(a=4) #return 4 R> f(b=33) #return 66 R> f(5) #error R> f(a=3,b=5) #error R> f(a=3,q=3) #error R> f(q=3) #error The following function is intended to implement this: f <- function(a=NULL, b=NULL){ if(!xor(is.null(a), is.null(b))){stop("specify exactly one of a and b")} if(is.null(a)){return(2*b)}else{return(a)} } It almost works, but f(6) returns 6 (and should be an error). What is the best way to accomplish my desired behaviour? -- Robin Hankin Uncertainty Analyst Southampton Oceanography Centre European Way, Southampton SO14 3ZH, UK tel 023-8059-7743
specify: f <- function(...,a=NULL,b=NULL) {...etc Bendix ---------------------- Bendix Carstensen Senior Statistician Steno Diabetes Center Niels Steensens Vej 2 DK-2820 Gentofte Denmark tel: +45 44 43 87 38 mob: +45 30 75 87 38 fax: +45 44 43 07 06 bxc at steno.dk www.biostat.ku.dk/~bxc ----------------------> -----Original Message----- > From: r-help-bounces at stat.math.ethz.ch > [mailto:r-help-bounces at stat.math.ethz.ch] On Behalf Of Robin Hankin > Sent: Friday, December 17, 2004 1:18 PM > To: R-help at stat.math.ethz.ch > Subject: [R] take precisely one named argument > > > Hi > > I want a function that takes precisely one named argument and > no unnamed arguments. The named argument must be one of "a" or "b". > > If "a" is supplied, return "a". If "b" is supplied, return > 2*b. That is, the desired behaviour is: > > R> f(a=4) #return 4 > R> f(b=33) #return 66 > R> f(5) #error > R> f(a=3,b=5) #error > R> f(a=3,q=3) #error > R> f(q=3) #error > > The following function is intended to implement this: > > f <- function(a=NULL, b=NULL){ > if(!xor(is.null(a), is.null(b))){stop("specify exactly one > of a and > b")} > if(is.null(a)){return(2*b)}else{return(a)} > } > > > It almost works, but f(6) returns 6 (and should be an error). > > What is the best way to accomplish my desired behaviour? > > -- > Robin Hankin > Uncertainty Analyst > Southampton Oceanography Centre > European Way, Southampton SO14 3ZH, UK > tel 023-8059-7743 > > ______________________________________________ > R-help at stat.math.ethz.ch mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read > the posting guide! http://www.R-project.org/posting-guide.html >
On 17-Dec-04 Robin Hankin wrote:> Hi > I want a function that takes precisely one named argument and no > unnamed arguments. The named argument must be one of "a" or "b". > > If "a" is supplied, return "a". If "b" is supplied, return 2*b. > That is, the desired behaviour is: > > R> f(a=4) #return 4 > R> f(b=33) #return 66 > R> f(5) #error > R> f(a=3,b=5) #error > R> f(a=3,q=3) #error > R> f(q=3) #error > > The following function is intended to implement this: >f <- function(a=NULL, b=NULL){ if(!xor(is.null(a), is.null(b))){ stop("specify exactly one of a and b") } if(is.null(a)){return(2*b)}else{return(a)} }> > > It almost works, but f(6) returns 6 (and should be an error). > > What is the best way to accomplish my desired behaviour?I don't know the *best* way (expert R anatomists will know ... ) but the following dirty handed modification seems to do what you want: f <- function(z=NULL, a=NULL, b=NULL){ if(!is.null(z)){ stop("usage: f(a=...) or f(b=...)") } if(!xor(is.null(a), is.null(b))){ stop("specify exactly one of a and b") } if(is.null(a)){return(2*b)}else{return(a)} } (This traps attempts to use f() with an un-named argument). Ted. -------------------------------------------------------------------- E-Mail: (Ted Harding) <Ted.Harding at nessie.mcc.ac.uk> Fax-to-email: +44 (0)870 094 0861 [NB: New number!] Date: 17-Dec-04 Time: 12:56:37 ------------------------------ XFMail ------------------------------
Here's my attempt:> f <- function(...) {+ argList <- list(...) + if (length(argList) != 1) stop("Wrong number of arguments!") + if (length(names(argList)) != 1 || ! names(argList) %in% c("a", "b")) + stop("Wrong name for argument!") + x <- argList[[1]] * if (names(argList) == "a") 1 else 2 + x + }> f(a=6)Error in f(6) : Wrong name for argument!> f(b=6)[1] 6> f(c=6)[1] 12> f(c=6)Error in f(c = 6) : Wrong name for argument! HTH, Andy> From: Robin Hankin > > Hi > > I want a function that takes precisely one named argument and no > unnamed arguments. The named argument must be one of "a" or "b". > > If "a" is supplied, return "a". If "b" is supplied, return 2*b. > That is, the desired behaviour is: > > R> f(a=4) #return 4 > R> f(b=33) #return 66 > R> f(5) #error > R> f(a=3,b=5) #error > R> f(a=3,q=3) #error > R> f(q=3) #error > > The following function is intended to implement this: > > f <- function(a=NULL, b=NULL){ > if(!xor(is.null(a), is.null(b))){stop("specify exactly one > of a and > b")} > if(is.null(a)){return(2*b)}else{return(a)} > } > > > It almost works, but f(6) returns 6 (and should be an error). > > What is the best way to accomplish my desired behaviour? > > -- > Robin Hankin > Uncertainty Analyst > Southampton Oceanography Centre > European Way, Southampton SO14 3ZH, UK > tel 023-8059-7743 > > ______________________________________________ > R-help at stat.math.ethz.ch mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide! > http://www.R-project.org/posting-guide.html > >
> From: Liaw, Andy > Here's my attempt: > > > f <- function(...) { > + argList <- list(...) > + if (length(argList) != 1) stop("Wrong number of arguments!") > + if (length(names(argList)) != 1 || ! names(argList) > %in% c("a", "b")) > + stop("Wrong name for argument!") > + x <- argList[[1]] * if (names(argList) == "a") 1 else 2 > + x > + } > > f(a=6) > Error in f(6) : Wrong name for argument! > > f(b=6) > [1] 6 > > f(c=6) > [1] 12This obviously _looks_ wrong, but that's only because I was running R under ESS, and up-arrowed to edit the commands. The correct transcript for this part ought to look like:> f(a=6)[1] 6> f(b=12)[1] 24> f(b=6)[1] 12> f(c=6)Error in f(c = 6) : Wrong name for argument! Andy> > f(c=6) > Error in f(c = 6) : Wrong name for argument! > > HTH, > Andy > > > > From: Robin Hankin > > > > Hi > > > > I want a function that takes precisely one named argument and no > > unnamed arguments. The named argument must be one of "a" or "b". > > > > If "a" is supplied, return "a". If "b" is supplied, return 2*b. > > That is, the desired behaviour is: > > > > R> f(a=4) #return 4 > > R> f(b=33) #return 66 > > R> f(5) #error > > R> f(a=3,b=5) #error > > R> f(a=3,q=3) #error > > R> f(q=3) #error > > > > The following function is intended to implement this: > > > > f <- function(a=NULL, b=NULL){ > > if(!xor(is.null(a), is.null(b))){stop("specify exactly one > > of a and > > b")} > > if(is.null(a)){return(2*b)}else{return(a)} > > } > > > > > > It almost works, but f(6) returns 6 (and should be an error). > > > > What is the best way to accomplish my desired behaviour? > > > > -- > > Robin Hankin > > Uncertainty Analyst > > Southampton Oceanography Centre > > European Way, Southampton SO14 3ZH, UK > > tel 023-8059-7743 > > > > ______________________________________________ > > R-help at stat.math.ethz.ch mailing list > > https://stat.ethz.ch/mailman/listinfo/r-help > > PLEASE do read the posting guide! > > http://www.R-project.org/posting-guide.html > > > > > > ______________________________________________ > R-help at stat.math.ethz.ch mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide! > http://www.R-project.org/posting-guide.html > > > -------------------------------------------------------------- > ---------------- > Notice: This e-mail message, together with any attachments, > contains information of Merck & Co., Inc. (One Merck Drive, > Whitehouse Station, New Jersey, USA 08889), and/or its > affiliates (which may be known outside the United States as > Merck Frosst, Merck Sharp & Dohme or MSD and in Japan, as > Banyu) that may be confidential, proprietary copyrighted > and/or legally privileged. It is intended solely for the use > of the individual or entity named on this message. If you > are not the intended recipient, and have received this > message in error, please notify us immediately by reply > e-mail and then delete it from your system. > -------------------------------------------------------------- > ---------------- >
Robin Hankin <r.hankin <at> soc.soton.ac.uk> writes: : : Hi : : I want a function that takes precisely one named argument and no : unnamed arguments. The named argument must be one of "a" or "b". : : If "a" is supplied, return "a". If "b" is supplied, return 2*b. : That is, the desired behaviour is: : : R> f(a=4) #return 4 : R> f(b=33) #return 66 : R> f(5) #error : R> f(a=3,b=5) #error : R> f(a=3,q=3) #error : R> f(q=3) #error : : The following function is intended to implement this: : : f <- function(a=NULL, b=NULL){ : if(!xor(is.null(a), is.null(b))){stop("specify exactly one of a and : b")} : if(is.null(a)){return(2*b)}else{return(a)} : } : : It almost works, but f(6) returns 6 (and should be an error). : : What is the best way to accomplish my desired behaviour? Here is one way to do it. nm are the names (where the [-1] removes the function name). The ... traps any arg that is not a or b and the stopifnot conditions ensure that exactly one of a and b are specified. ff <- function(..., a = 0, b = 0) { nm <- names(match.call()[-1]) stopifnot(length(nm) == 1, nm %in% c("a", "b")) a+2*b } One thing to watch out for is that if
Gabor Grothendieck <ggrothendieck <at> myway.com> writes: : : Robin Hankin <r.hankin <at> soc.soton.ac.uk> writes: : : : : : Hi : : : : I want a function that takes precisely one named argument and no : : unnamed arguments. The named argument must be one of "a" or "b". : : : : If "a" is supplied, return "a". If "b" is supplied, return 2*b. : : That is, the desired behaviour is: : : : : R> f(a=4) #return 4 : : R> f(b=33) #return 66 : : R> f(5) #error : : R> f(a=3,b=5) #error : : R> f(a=3,q=3) #error : : R> f(q=3) #error : : : : The following function is intended to implement this: : : : : f <- function(a=NULL, b=NULL){ : : if(!xor(is.null(a), is.null(b))){stop("specify exactly one of a and : : b")} : : if(is.null(a)){return(2*b)}else{return(a)} : : } : : : : It almost works, but f(6) returns 6 (and should be an error). : : : : What is the best way to accomplish my desired behaviour? : : Here is one way to do it. nm are the names (where the [-1] removes : the function name). The ... traps any arg that is not a or b and the : stopifnot conditions ensure that exactly one of a and b are specified. : : ff <- function(..., a = 0, b = 0) { : nm <- names(match.call()[-1]) : stopifnot(length(nm) == 1, nm %in% c("a", "b")) : a+2*b : } : : One thing to watch out for is that if Seems this got cut off somehow. I was going to mention that while the above works, if the variables are aa and bb rather than a and b then ... results in only exact matches working. That is a or b will be trapped by ... so only aa written exactly and bb written exactly will match the aa and bb args. Also, one could replace c("a", "b") with names(formals()[-1]) which would make it easier to change variable names or add more variable names in the future since the condition would not change.