Re: [Rd] Creating functions programmatically

From: Hadley Wickham <h.wickham_at_gmail.com>
Date: Wed, 03 Oct 2012 17:55:17 -0500

> I think `function` does not eval its arguments, and it demands a
> pairlist. So this works:
>
> f <- eval(substitute(`function`(args, body),
> list(args=as.pairlist(alist(a=1)), body=quote(a+1))))
>
> The other thing to notice is a syntax difference between function and
> ordinary calls: when writing

Thanks.

So as far as I can tell, we have 4 basic ways of making a function from args, body and env:

    make_function1 <- function(args, body, env = parent.frame()) {

      args <- as.pairlist(args)
      eval(call("function", args, body), env)
    }
    make_function2 <- function(args, body, env = parent.frame()) {
      f <- function() {}
      formals(f) <- args
      body(f) <- body
      environment(f) <- env

      f

    }
    make_function3 <- function(args, body, env = parent.frame()) {       as.function(c(args, body), env)
    }
    make_function4 <- function(args, body, env = parent.frame()) {
      subs <- list(args = as.pairlist(args), body = body)
      eval(substitute(`function`(args, body), subs), env)
    }

    args <- alist(a = 1, b = 2)
    body <- quote(a + b)

    make_function1(args, body)
    make_function2(args, body)
    make_function3(args, body)
    make_function4(args, body)

And not that speed really matters much here, but:

    library(microbenchmark)
    microbenchmark(

      make_function1(args, body),
      make_function2(args, body),
      make_function3(args, body),
      make_function4(args, body),
      function(a = 1, b = 2) a + b

    )

Unit: nanoseconds

                          expr   min    lq median    uq    max
1 function(a = 1, b = 2) a + b 165 228 279 330 703
2   make_function1(args, body)  3540  4276   4774  5340  12947
3   make_function2(args, body) 47150 49170  49972 52510 147753
4   make_function3(args, body)  7461  8482   9116  9515  14763
5   make_function4(args, body)  4818  5814   6424  7102  13385

So constructing the call explicitly is fastest, followed by using function, then as.function. Modifying an empty function is an order of magnitude slower. Even the fastest approach is about 20x slower than creating it by hand.

Hadley

-- 
RStudio / Rice University
http://had.co.nz/

______________________________________________
R-devel_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Received on Wed 03 Oct 2012 - 22:57:49 GMT

This quarter's messages: by month, or sorted: [ by date ] [ by thread ] [ by subject ] [ by author ]

All messages

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Thu 04 Oct 2012 - 03:20:44 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-devel. Please read the posting guide before posting to the list.

list of date sections of archive