|
[ please copy me on answers, since I am not subscribed to the list ]
Dear all, I am trying to write an R function which uses system.time to determine which of a given list of R expressions executes fastest. To work around the limited resolution of system.time, I want to convert the given expressions into functions which execute the given expressions a fixed number of times. My current attempt is as follows: FuncIt <- function(k, expr) { k <- as.numeric(k) expr <- eval.parent(substitute(expr)) eval(substitute(function() { for (funcit.i in 1:k) { expr } })) } This works, but seems not very robust. My question: is there a better way of doing this? Here are some experiments. 1) good: If I run the following using "Rscript" test1 <- function(e1) { e1 <- substitute(e1) FuncIt(100, e1) } f <- test1(rnorm(1)) print(f) then I get the following output: function () { for (funcit.i in 1:100) { rnorm(1) } } <environment: 0x102260c28> This is what I want. But why do I need the extra "substitute" in test1? I only found by experiment that this is needed. 2) bad: If I try to call FuncIt directly, it fails: f <- FuncIt(100, rnorm(1)) print(f) has the output: function () { for (funcit.i in 1:100) { -0.763894772833099 } } <environment: 0x102265790> This is bad, since now 'rnorm(1)' already has been evaluated. How do I prevent this from happening, without breaking the good case 1 above? 3) ugly: If I run the same commands in the R gui on MacOS (R 2.15.1 released on 2012/06/22), I get different output: > source("/Users/voss/project/statcomp/test.R") function() { for (funcit.i in 1:k) { expr } } <environment: 0x19cc040> function() { for (funcit.i in 1:k) { expr } } <environment: 0x19bc884> This is on the same machine using (as far as I can tell) the same R engine. So why is the output different? Many thanks, Jochen -- http://seehuhn.de/ ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
]On Sat, Jun 30, 2012 at 2:36 AM, Jochen Voß <[hidden email]> wrote:
> [ please copy me on answers, since I am not subscribed to the list ] > > Dear all, > > I am trying to write an R function which uses system.time > to determine which of a given list of R expressions executes > fastest. To work around the limited resolution of system.time, > I want to convert the given expressions into functions which > execute the given expressions a fixed number of times. > My current attempt is as follows: > > FuncIt <- function(k, expr) { > k <- as.numeric(k) > expr <- eval.parent(substitute(expr)) > eval(substitute(function() { for (funcit.i in 1:k) { expr } })) > } > > This works, but seems not very robust. > My question: is there a better way of doing this? > > Here are some experiments. > > 1) good: If I run the following using "Rscript" > > test1 <- function(e1) { > e1 <- substitute(e1) > FuncIt(100, e1) > } > > f <- test1(rnorm(1)) > print(f) > > then I get the following output: > > function () > { > for (funcit.i in 1:100) { > rnorm(1) > } > } > <environment: 0x102260c28> > > This is what I want. But why do I need the extra "substitute" > in test1? I only found by experiment that this is needed. You don't. You need an extra quote() in the argument. That is, rnorm(1) is a call to the rnorm() function. Since R passes by value, the formal argument e1 is evaluated, returning a number, and that is what ends up in your code. If you want to pass a piece of unevaluated code to a function you should ideally use quote() or expression() to wrap it, so that it is not evaluated. You can get around this using substitute(), which extracts the unevaluated code from the formal argument, but it's probably a bad idea, since the user of the function should expect all the arguments to be evaluated. > > 2) bad: If I try to call FuncIt directly, it fails: > > f <- FuncIt(100, rnorm(1)) > print(f) > > has the output: > > function () > { > for (funcit.i in 1:100) { > -0.763894772833099 > } > } > <environment: 0x102265790> > > This is bad, since now 'rnorm(1)' already has been > evaluated. How do I prevent this from happening, > without breaking the good case 1 above? > Use quote() or expression() rather than trying to trick the evaluator. > 3) ugly: If I run the same commands in the R gui on MacOS > (R 2.15.1 released on 2012/06/22), I get different output: > >> source("/Users/voss/project/statcomp/test.R") > function() { for (funcit.i in 1:k) { expr } } > <environment: 0x19cc040> > function() { for (funcit.i in 1:k) { expr } } > <environment: 0x19bc884> > > This is on the same machine using (as far as I can tell) the > same R engine. So why is the output different? The "ugly" formatting is how you formatted the code in the call to eval(), and the good formatting is how R would print it without any source constraints, so this is probably something to do with the keep.source= argument source(). -thomas -- Thomas Lumley Professor of Biostatistics University of Auckland ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
In reply to this post by Jochen Voß
Look at the replicate function, it takes an expression (does not need
a function) and runs that expression the specified number of times. Will that accomplish what you want without needing to worry about substitute, quote, eval, etc.? On Fri, Jun 29, 2012 at 11:36 AM, Jochen Voß <[hidden email]> wrote: > [ please copy me on answers, since I am not subscribed to the list ] > > Dear all, > > I am trying to write an R function which uses system.time > to determine which of a given list of R expressions executes > fastest. To work around the limited resolution of system.time, > I want to convert the given expressions into functions which > execute the given expressions a fixed number of times. > My current attempt is as follows: > > FuncIt <- function(k, expr) { > k <- as.numeric(k) > expr <- eval.parent(substitute(expr)) > eval(substitute(function() { for (funcit.i in 1:k) { expr } })) > } > > This works, but seems not very robust. > My question: is there a better way of doing this? > > Here are some experiments. > > 1) good: If I run the following using "Rscript" > > test1 <- function(e1) { > e1 <- substitute(e1) > FuncIt(100, e1) > } > > f <- test1(rnorm(1)) > print(f) > > then I get the following output: > > function () > { > for (funcit.i in 1:100) { > rnorm(1) > } > } > <environment: 0x102260c28> > > This is what I want. But why do I need the extra "substitute" > in test1? I only found by experiment that this is needed. > > > 2) bad: If I try to call FuncIt directly, it fails: > > f <- FuncIt(100, rnorm(1)) > print(f) > > has the output: > > function () > { > for (funcit.i in 1:100) { > -0.763894772833099 > } > } > <environment: 0x102265790> > > This is bad, since now 'rnorm(1)' already has been > evaluated. How do I prevent this from happening, > without breaking the good case 1 above? > > > 3) ugly: If I run the same commands in the R gui on MacOS > (R 2.15.1 released on 2012/06/22), I get different output: > >> source("/Users/voss/project/statcomp/test.R") > function() { for (funcit.i in 1:k) { expr } } > <environment: 0x19cc040> > function() { for (funcit.i in 1:k) { expr } } > <environment: 0x19bc884> > > This is on the same machine using (as far as I can tell) the > same R engine. So why is the output different? > > > Many thanks, > Jochen > -- > http://seehuhn.de/ > > ______________________________________________ > [hidden email] mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. -- Gregory (Greg) L. Snow Ph.D. [hidden email] ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
On 30 June 2012 at 11:39, Greg Snow wrote: | Look at the replicate function, it takes an expression (does not need | a function) and runs that expression the specified number of times. | Will that accomplish what you want without needing to worry about | substitute, quote, eval, etc.? And also look at the existing benchmark packages 'rbenchmark' and 'microbenchmark': R> library(microbenchmark) R> x <- 5; microbenchmark( 1/x, x^-1 ) Unit: nanoseconds expr min lq median uq max 1 1/x 296 322.5 341 364.0 6298 2 x^-1 516 548.5 570 591.5 5422 R> Dirk -- Dirk Eddelbuettel | [hidden email] | http://dirk.eddelbuettel.com ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
In reply to this post by Thomas Lumley-2
Dear Thomas,
Many thanks for your answer. On Sat, Jun 30, 2012 at 10:22:52AM +0900, Thomas Lumley wrote: > > 1) good: If I run the following using "Rscript" > > > > test1 <- function(e1) { > > e1 <- substitute(e1) > > FuncIt(100, e1) > > } > > > > f <- test1(rnorm(1)) > > print(f) > > > > then I get the following output: > > > > function () > > { > > for (funcit.i in 1:100) { > > rnorm(1) > > } > > } > > <environment: 0x102260c28> > > > > This is what I want. But why do I need the extra "substitute" > > in test1? I only found by experiment that this is needed. > > You don't. You need an extra quote() in the argument. > [...] > You can get around this using substitute(), which extracts the > unevaluated code from the formal argument, but it's probably a bad > idea, since the user of the function should expect all the arguments > to be evaluated. I want my final function to work like system.time, i.e. the user should not have to type "quote()" all the time when calling the top-level function of my measuring mechanism. Is there a way to do the quoting inside the top-level function call? Many thanks, Jochen Voss -- http://seehuhn.de/ ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
In reply to this post by glsnow
Dear Greg,
many thanks for your anwer. On Sat, Jun 30, 2012 at 11:39:07AM -0600, Greg Snow wrote: > Look at the replicate function, it takes an expression (does not need > a function) and runs that expression the specified number of times. > Will that accomplish what you want without needing to worry about > substitute, quote, eval, etc.? Yes, this is very similar to what I want to achieve. One of the main differences is that 'replicate' builds up a list of all call results, and for my measurements I want to avoid the resulting (time and memory) overhead. But I did look at the implementation of 'replicate' and this is where I took the trick of using eval.parent and substitute from. All the best, Jochen -- http://seehuhn.de/ ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
In reply to this post by Dirk Eddelbuettel
Dear Dirk,
On Sat, Jun 30, 2012 at 01:28:13PM -0500, Dirk Eddelbuettel wrote: > And also look at the existing benchmark packages 'rbenchmark' and > 'microbenchmark': Many thanks for pointing out these packages, I wasn't aware of these. > R> library(microbenchmark) > R> x <- 5; microbenchmark( 1/x, x^-1 ) > Unit: nanoseconds > expr min lq median uq max > 1 1/x 296 322.5 341 364.0 6298 > 2 x^-1 516 548.5 570 591.5 5422 My own code (current version attached, comments would be very welcome) is much more "chatty": > R> source("timeit.R") > R> x <- 5; TimeIt(1/x, x^-1) > tuning ... > measuring 10*1466753 samples for each expression ... > |======================================================================| 100% > > execution time comparison: > 1/x (0.000571 ± 1.48e-05) ms/call > x^-1 (0.000864 ± 9.69e-06) ms/call > CI for difference: [-0.00031, -0.000275] ms/call > > '1/x' is about 33.9% faster (p=2.75e-11) ability to compare more than two expressions in one call. But unfortunately, I haven't found out so far whether (and if so, how) it is possible to extract the elements of a "..." object without evaluating them. Many thanks, Jochen -- http://seehuhn.de/ ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
> One of the things I would love to add to my package would be the
> ability to compare more than two expressions in one call. But > unfortunately, I haven't found out so far whether (and if so, how) it > is possible to extract the elements of a "..." object without > evaluating them. Have a look at match.call. Hadley -- Assistant Professor / Dobelman Family Junior Chair Department of Statistics / Rice University http://had.co.nz/ ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
>> One of the things I would love to add to my package would be the
>> ability to compare more than two expressions in one call. But >> unfortunately, I haven't found out so far whether (and if so, how) it >> is possible to extract the elements of a "..." object without >> evaluating them. > >Have a look at match.call. ... or use dotlist <- list(...) to get a list of everything included in ... S Ellison ******************************************************************* This email and any attachments are confidential. Any use...{{dropped:8}} ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
On Mon, Jul 23, 2012 at 2:12 PM, S Ellison <[hidden email]> wrote:
>>> One of the things I would love to add to my package would be the >>> ability to compare more than two expressions in one call. But >>> unfortunately, I haven't found out so far whether (and if so, how) it >>> is possible to extract the elements of a "..." object without >>> evaluating them. >> >>Have a look at match.call. > > ... or use > dotlist <- list(...) > > to get a list of everything included in ... But that evaluates them, which I don't think the original poster wanted. Hadley -- Assistant Professor / Dobelman Family Junior Chair Department of Statistics / Rice University http://had.co.nz/ ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
In reply to this post by S Ellison-2
list(...) evaluates the things in ...
E.g., > f0 <- function(x, ...) list(...) > f0(1, warning("Hmm"), stop("Oops"), cat("some output\n"))[[2]] Error in f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Oops In addition: Warning message: In f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Hmm You can use the odd idiom substitute(...()) to get the unevaluated ... arguments: > f1 <- function(x, ...) substitute(...()) > f1(1, warning("Hmm"), stop("Oops"), cat("some output\n")) [[1]] warning("Hmm") [[2]] stop("Oops") [[3]] cat("some output\n") Bill Dunlap Spotfire, TIBCO Software wdunlap tibco.com > -----Original Message----- > From: [hidden email] [mailto:[hidden email]] On > Behalf Of S Ellison > Sent: Monday, July 23, 2012 2:12 PM > To: Jochen Voß > Cc: [hidden email] > Subject: Re: [R] turning R expressions into functions? > > >> One of the things I would love to add to my package would be the > >> ability to compare more than two expressions in one call. But > >> unfortunately, I haven't found out so far whether (and if so, how) it > >> is possible to extract the elements of a "..." object without > >> evaluating them. > > > >Have a look at match.call. > > ... or use > dotlist <- list(...) > > to get a list of everything included in ... > > S Ellison > > ***************************************************************** > ** > This email and any attachments are confidential. Any use...{{dropped:8}} > > ______________________________________________ > [hidden email] mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
Bill:
Is there some reason to prefer your "odd idiom" to match.call, perhaps as as.list(match.call()), as proposed by Hadley? -- Bert On Mon, Jul 23, 2012 at 2:25 PM, William Dunlap <[hidden email]> wrote: > list(...) evaluates the things in ... > E.g., > > f0 <- function(x, ...) list(...) > > f0(1, warning("Hmm"), stop("Oops"), cat("some output\n"))[[2]] > Error in f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Oops > In addition: Warning message: > In f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Hmm > > You can use the odd idiom substitute(...()) to get the unevaluated ... arguments: > > f1 <- function(x, ...) substitute(...()) > > f1(1, warning("Hmm"), stop("Oops"), cat("some output\n")) > [[1]] > warning("Hmm") > > [[2]] > stop("Oops") > > [[3]] > cat("some output\n") > > > Bill Dunlap > Spotfire, TIBCO Software > wdunlap tibco.com > > >> -----Original Message----- >> From: [hidden email] [mailto:[hidden email]] On >> Behalf Of S Ellison >> Sent: Monday, July 23, 2012 2:12 PM >> To: Jochen Voß >> Cc: [hidden email] >> Subject: Re: [R] turning R expressions into functions? >> >> >> One of the things I would love to add to my package would be the >> >> ability to compare more than two expressions in one call. But >> >> unfortunately, I haven't found out so far whether (and if so, how) it >> >> is possible to extract the elements of a "..." object without >> >> evaluating them. >> > >> >Have a look at match.call. >> >> ... or use >> dotlist <- list(...) >> >> to get a list of everything included in ... >> >> S Ellison >> >> ***************************************************************** >> ** >> This email and any attachments are confidential. Any use...{{dropped:8}} >> >> ______________________________________________ >> [hidden email] mailing list >> https://stat.ethz.ch/mailman/listinfo/r-help >> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html >> and provide commented, minimal, self-contained, reproducible code. > > ______________________________________________ > [hidden email] mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. -- Bert Gunter Genentech Nonclinical Biostatistics Internal Contact Info: Phone: 467-7374 Website: http://pharmadevelopment.roche.com/index/pdb/pdb-functional-groups/pdb-biostatistics/pdb-ncb-home.htm ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
... or better still, the idiom used in update.default:
match.call(expand.dots=FALSE)$... ? -- Bert On Mon, Jul 23, 2012 at 2:45 PM, Bert Gunter <[hidden email]> wrote: > Bill: > > Is there some reason to prefer your "odd idiom" to match.call, perhaps > as as.list(match.call()), as proposed by Hadley? > > -- Bert > > On Mon, Jul 23, 2012 at 2:25 PM, William Dunlap <[hidden email]> wrote: >> list(...) evaluates the things in ... >> E.g., >> > f0 <- function(x, ...) list(...) >> > f0(1, warning("Hmm"), stop("Oops"), cat("some output\n"))[[2]] >> Error in f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Oops >> In addition: Warning message: >> In f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Hmm >> >> You can use the odd idiom substitute(...()) to get the unevaluated ... arguments: >> > f1 <- function(x, ...) substitute(...()) >> > f1(1, warning("Hmm"), stop("Oops"), cat("some output\n")) >> [[1]] >> warning("Hmm") >> >> [[2]] >> stop("Oops") >> >> [[3]] >> cat("some output\n") >> >> >> Bill Dunlap >> Spotfire, TIBCO Software >> wdunlap tibco.com >> >> >>> -----Original Message----- >>> From: [hidden email] [mailto:[hidden email]] On >>> Behalf Of S Ellison >>> Sent: Monday, July 23, 2012 2:12 PM >>> To: Jochen Voß >>> Cc: [hidden email] >>> Subject: Re: [R] turning R expressions into functions? >>> >>> >> One of the things I would love to add to my package would be the >>> >> ability to compare more than two expressions in one call. But >>> >> unfortunately, I haven't found out so far whether (and if so, how) it >>> >> is possible to extract the elements of a "..." object without >>> >> evaluating them. >>> > >>> >Have a look at match.call. >>> >>> ... or use >>> dotlist <- list(...) >>> >>> to get a list of everything included in ... >>> >>> S Ellison >>> >>> ***************************************************************** >>> ** >>> This email and any attachments are confidential. Any use...{{dropped:8}} >>> >>> ______________________________________________ >>> [hidden email] mailing list >>> https://stat.ethz.ch/mailman/listinfo/r-help >>> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html >>> and provide commented, minimal, self-contained, reproducible code. >> >> ______________________________________________ >> [hidden email] mailing list >> https://stat.ethz.ch/mailman/listinfo/r-help >> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html >> and provide commented, minimal, self-contained, reproducible code. > > > > -- > > Bert Gunter > Genentech Nonclinical Biostatistics > > Internal Contact Info: > Phone: 467-7374 > Website: > http://pharmadevelopment.roche.com/index/pdb/pdb-functional-groups/pdb-biostatistics/pdb-ncb-home.htm -- Bert Gunter Genentech Nonclinical Biostatistics Internal Contact Info: Phone: 467-7374 Website: http://pharmadevelopment.roche.com/index/pdb/pdb-functional-groups/pdb-biostatistics/pdb-ncb-home.htm ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
In reply to this post by Bert Gunter
I tend not to use match.call for this because it feels like I'm repeating
work (argument matching) that has already been done. Also, match.call's output needs to be processed a bit to get the expressions. The following 2 functions give the same results, a "pairlist" of the unevaluated arguments matching the "..." in the function definition. f1 <- function(x, ..., atEnd) substitute(...()) f2 <- function(x, ..., atEnd) match.call(expand.dots=FALSE)$... E.g., > str(f1(1, stop("don't evaluate me!"), Log=log(-10:1), atEnd=Inf)) Dotted pair list of 2 $ : language stop("don't evaluate me!") $ Log: language log(-10:1) > str(f2(1, stop("don't evaluate me!"), Log=log(-10:1), atEnd=Inf)) Dotted pair list of 2 $ : language stop("don't evaluate me!") $ Log: language log(-10:1) The former appears to be about 3 times as fast as the latter, but you need to run it a lot of times (>10^4) to see the difference. There may be a bigger speedup if there are lots of non-"..." arguments, but I haven't tested that. I also use the following, which works in both S+ and R: > f3 <- function(x, ..., atEnd) as.list(substitute(junk(...)))[-1] > str(f3(1, stop("don't evaluate me!"), Log=log(-10:1), atEnd=Inf)) List of 2 $ : language stop("don't evaluate me!") $ Log: language log(-10:1) It is probably best to bury this in a utility function with an intuitive name instead of trying to remember the idioms. Perhaps there already is one. Bill Dunlap Spotfire, TIBCO Software wdunlap tibco.com > -----Original Message----- > From: Bert Gunter [mailto:[hidden email]] > Sent: Monday, July 23, 2012 2:45 PM > To: William Dunlap > Cc: S Ellison; Jochen Voß; [hidden email] > Subject: Re: [R] turning R expressions into functions? > > Bill: > > Is there some reason to prefer your "odd idiom" to match.call, perhaps > as as.list(match.call()), as proposed by Hadley? > > -- Bert > > On Mon, Jul 23, 2012 at 2:25 PM, William Dunlap <[hidden email]> wrote: > > list(...) evaluates the things in ... > > E.g., > > > f0 <- function(x, ...) list(...) > > > f0(1, warning("Hmm"), stop("Oops"), cat("some output\n"))[[2]] > > Error in f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Oops > > In addition: Warning message: > > In f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Hmm > > > > You can use the odd idiom substitute(...()) to get the unevaluated ... arguments: > > > f1 <- function(x, ...) substitute(...()) > > > f1(1, warning("Hmm"), stop("Oops"), cat("some output\n")) > > [[1]] > > warning("Hmm") > > > > [[2]] > > stop("Oops") > > > > [[3]] > > cat("some output\n") > > > > > > Bill Dunlap > > Spotfire, TIBCO Software > > wdunlap tibco.com > > > > > >> -----Original Message----- > >> From: [hidden email] [mailto:[hidden email]] On > >> Behalf Of S Ellison > >> Sent: Monday, July 23, 2012 2:12 PM > >> To: Jochen Voß > >> Cc: [hidden email] > >> Subject: Re: [R] turning R expressions into functions? > >> > >> >> One of the things I would love to add to my package would be the > >> >> ability to compare more than two expressions in one call. But > >> >> unfortunately, I haven't found out so far whether (and if so, how) it > >> >> is possible to extract the elements of a "..." object without > >> >> evaluating them. > >> > > >> >Have a look at match.call. > >> > >> ... or use > >> dotlist <- list(...) > >> > >> to get a list of everything included in ... > >> > >> S Ellison > >> > >> > ***************************************************************** > >> ** > >> This email and any attachments are confidential. Any use...{{dropped:8}} > >> > >> ______________________________________________ > >> [hidden email] mailing list > >> https://stat.ethz.ch/mailman/listinfo/r-help > >> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > >> and provide commented, minimal, self-contained, reproducible code. > > > > ______________________________________________ > > [hidden email] mailing list > > https://stat.ethz.ch/mailman/listinfo/r-help > > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > > and provide commented, minimal, self-contained, reproducible code. > > > > -- > > Bert Gunter > Genentech Nonclinical Biostatistics > > Internal Contact Info: > Phone: 467-7374 > Website: > http://pharmadevelopment.roche.com/index/pdb/pdb-functional-groups/pdb- > biostatistics/pdb-ncb-home.htm [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
OK Bill, et, al:
I prefer your 3rd form buried in dotsArgs as: dotsArgs <- function()as.list(substitute((...),env=parent.frame()))[-1] ##testit > f <- function(x, ..., atEnd) dotsArgs() > str(f(1, stop("don't evaluate me!"), Log=log(-10:1), atEnd=Inf)) List of 2 $ : language stop("don't evaluate me!") $ Log: language log(-10:1) Let me know if you see any problems (if you care to bother with it) -- Bert On Mon, Jul 23, 2012 at 3:04 PM, William Dunlap <[hidden email]> wrote: > I tend not to use match.call for this because it feels like I'm repeating > work (argument matching) that has already been done. Also, match.call's > output needs to be processed a bit to get the expressions. > > The following 2 functions give the same results, a "pairlist" of the unevaluated > arguments matching the "..." in the function definition. > f1 <- function(x, ..., atEnd) substitute(...()) > f2 <- function(x, ..., atEnd) match.call(expand.dots=FALSE)$... > E.g., > > str(f1(1, stop("don't evaluate me!"), Log=log(-10:1), atEnd=Inf)) > Dotted pair list of 2 > $ : language stop("don't evaluate me!") > $ Log: language log(-10:1) > > str(f2(1, stop("don't evaluate me!"), Log=log(-10:1), atEnd=Inf)) > Dotted pair list of 2 > $ : language stop("don't evaluate me!") > $ Log: language log(-10:1) > The former appears to be about 3 times as fast as the latter, but you need > to run it a lot of times (>10^4) to see the difference. There may be a bigger > speedup if there are lots of non-"..." arguments, but I haven't tested that. > > I also use the following, which works in both S+ and R: > > f3 <- function(x, ..., atEnd) as.list(substitute(junk(...)))[-1] > > str(f3(1, stop("don't evaluate me!"), Log=log(-10:1), atEnd=Inf)) > List of 2 > $ : language stop("don't evaluate me!") > $ Log: language log(-10:1) > > It is probably best to bury this in a utility function with an intuitive name instead > of trying to remember the idioms. Perhaps there already is one. > > Bill Dunlap > Spotfire, TIBCO Software > wdunlap tibco.com > > >> -----Original Message----- >> From: Bert Gunter [mailto:[hidden email]] >> Sent: Monday, July 23, 2012 2:45 PM >> To: William Dunlap >> Cc: S Ellison; Jochen Voß; [hidden email] >> Subject: Re: [R] turning R expressions into functions? >> >> Bill: >> >> Is there some reason to prefer your "odd idiom" to match.call, perhaps >> as as.list(match.call()), as proposed by Hadley? >> >> -- Bert >> >> On Mon, Jul 23, 2012 at 2:25 PM, William Dunlap <[hidden email]> wrote: >> > list(...) evaluates the things in ... >> > E.g., >> > > f0 <- function(x, ...) list(...) >> > > f0(1, warning("Hmm"), stop("Oops"), cat("some output\n"))[[2]] >> > Error in f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Oops >> > In addition: Warning message: >> > In f0(1, warning("Hmm"), stop("Oops"), cat("some output\n")) : Hmm >> > >> > You can use the odd idiom substitute(...()) to get the unevaluated ... arguments: >> > > f1 <- function(x, ...) substitute(...()) >> > > f1(1, warning("Hmm"), stop("Oops"), cat("some output\n")) >> > [[1]] >> > warning("Hmm") >> > >> > [[2]] >> > stop("Oops") >> > >> > [[3]] >> > cat("some output\n") >> > >> > >> > Bill Dunlap >> > Spotfire, TIBCO Software >> > wdunlap tibco.com >> > >> > >> >> -----Original Message----- >> >> From: [hidden email] [mailto:[hidden email]] On >> >> Behalf Of S Ellison >> >> Sent: Monday, July 23, 2012 2:12 PM >> >> To: Jochen Voß >> >> Cc: [hidden email] >> >> Subject: Re: [R] turning R expressions into functions? >> >> >> >> >> One of the things I would love to add to my package would be the >> >> >> ability to compare more than two expressions in one call. But >> >> >> unfortunately, I haven't found out so far whether (and if so, how) it >> >> >> is possible to extract the elements of a "..." object without >> >> >> evaluating them. >> >> > >> >> >Have a look at match.call. >> >> >> >> ... or use >> >> dotlist <- list(...) >> >> >> >> to get a list of everything included in ... >> >> >> >> S Ellison >> >> >> >> >> ***************************************************************** >> >> ** >> >> This email and any attachments are confidential. Any use...{{dropped:8}} >> >> >> >> ______________________________________________ >> >> [hidden email] mailing list >> >> https://stat.ethz.ch/mailman/listinfo/r-help >> >> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html >> >> and provide commented, minimal, self-contained, reproducible code. >> > >> > ______________________________________________ >> > [hidden email] mailing list >> > https://stat.ethz.ch/mailman/listinfo/r-help >> > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html >> > and provide commented, minimal, self-contained, reproducible code. >> >> >> >> -- >> >> Bert Gunter >> Genentech Nonclinical Biostatistics >> >> Internal Contact Info: >> Phone: 467-7374 >> Website: >> http://pharmadevelopment.roche.com/index/pdb/pdb-functional-groups/pdb- >> biostatistics/pdb-ncb-home.htm -- Bert Gunter Genentech Nonclinical Biostatistics Internal Contact Info: Phone: 467-7374 Website: http://pharmadevelopment.roche.com/index/pdb/pdb-functional-groups/pdb-biostatistics/pdb-ncb-home.htm ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
|
In reply to this post by William Dunlap
Dear all,
Sorry for my slow answer, and thanks for all the suggestion. On 23 Jul 2012, at 22:25, William Dunlap <[hidden email]> wrote: > You can use the odd idiom substitute(...()) to get the unevaluated ... arguments: >> f1 <- function(x, ...) substitute(...()) >> f1(1, warning("Hmm"), stop("Oops"), cat("some output\n")) This is what I finally settled on using. Many thanks, Jochen -- http://seehuhn.de/ ______________________________________________ [hidden email] mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. |
| Powered by Nabble | Edit this page |
