Dear list
# I have a function
ff <- function(a,b=2,c=4){a+b+c}
# which I programmatically want to modify to a more specialized function in which a is replaced by 1
ff1 <- function(b=2,c=4){1+b+c}
# I do as follows:
vals <- list(a=1)
(expr1 <- as.expression(body(ff)))
expression({
a + b + c
})
(expr2 <- do.call("substitute", list(expr1[[1]], vals)))
{
1 + b + c
}
# This "works",
eval(expr2, list(b=10,c=12))
[1] 23
# - but I would like a function. Hence I do:
ll <- alist(b=, c=, eval(expr2))
ff2 <- as.function(ll)
ff2(b=10,c=12)
[1] 23
# BUT I am only half-way where I want to be because the alist(b=, c=, ...)
# requires me plugin the remaining formals by hand. I do:
newformals <-setdiff(names(formals(ff)), names(vals))
vv <- vector("list", length(newformals))
names(vv) <- newformals
(hh <- c(vv, expr2))
$b
NULL
$c
NULL
[[3]]
{
1 + b + c
}
(ff3 <- as.function(hh))
function (b = NULL, c = NULL)
{
1 + b + c
}
ff3(10,12)
[1] 23
# Hence I get the function that returns what I want (given the correct input)
# but the arguments will have default values that I don't want.
# I want to retain the original default values (if any)
ff1()
[1] 7
ff3()
numeric(0)
I have two questions:
1) How to fix the above?
2) Aren't there more elegant alternatives?
Any help would be appreciated.
Regards
S?ren
Modifying a function programmatically
5 messages · Søren Højsgaard, Pascal Oettli, Gabor Grothendieck
Hi,
Is it what you are looking for?
> ff <- function(a,b,c){a+b+c}
> ff(1,10,12)
[1] 23
> ff(589,2,4)
[1] 595
HTH,
Pascal
Le 04/02/2013 19:00, S?ren H?jsgaard a ?crit :
Dear list
# I have a function
ff <- function(a,b=2,c=4){a+b+c}
# which I programmatically want to modify to a more specialized function in which a is replaced by 1
ff1 <- function(b=2,c=4){1+b+c}
# I do as follows:
vals <- list(a=1)
(expr1 <- as.expression(body(ff)))
expression({
a + b + c
})
(expr2 <- do.call("substitute", list(expr1[[1]], vals)))
{
1 + b + c
}
# This "works",
eval(expr2, list(b=10,c=12))
[1] 23
# - but I would like a function. Hence I do:
ll <- alist(b=, c=, eval(expr2))
ff2 <- as.function(ll)
ff2(b=10,c=12)
[1] 23
# BUT I am only half-way where I want to be because the alist(b=, c=, ...)
# requires me plugin the remaining formals by hand. I do:
newformals <-setdiff(names(formals(ff)), names(vals))
vv <- vector("list", length(newformals))
names(vv) <- newformals
(hh <- c(vv, expr2))
$b
NULL
$c
NULL
[[3]]
{
1 + b + c
}
(ff3 <- as.function(hh))
function (b = NULL, c = NULL)
{
1 + b + c
}
ff3(10,12)
[1] 23
# Hence I get the function that returns what I want (given the correct input)
# but the arguments will have default values that I don't want.
# I want to retain the original default values (if any)
ff1()
[1] 7
ff3()
numeric(0)
I have two questions:
1) How to fix the above?
2) Aren't there more elegant alternatives?
Any help would be appreciated.
Regards
S?ren
______________________________________________ R-help at r-project.org 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.
No, this is not really what I want. But I have (later) realized that what I am looking for can be achieved as shown below. I am just not sure how bullet-proof the solution is. Suggestions are welcome!
Regards
S?ren
------------------------------------------
specialize <- function(ff, vals){
expr1 <- as.expression(body(ff))
expr2 <- do.call("substitute", list(expr1[[1]], vals))
gg <- formals(ff)
idx <-match(names(vals), names(gg))
gg <- gg[-idx]
as.function(c(gg, expr2))
}
ff <- function(a,b=2,c=4){a+b+c}
(ans<-specialize(ff, list(a=1)))
function (b = 2, c = 4)
{
1 + b + c
}
<environment: 0x0000000008b51c68>
ans()
[1] 7
ans(b=10)
[1] 15
(ans<-specialize(rnorm, list(n=10)))
function (mean = 0, sd = 1)
.Internal(rnorm(10, mean, sd))
<environment: 0x0000000008b5a0b8>
ans()
[1] 0.1783645319 2.1151344735 -0.6744270178 0.0009751497 -0.1477708270 0.1710790055
[7] -0.0064331250 0.5935787352 -0.1426050990 -0.1390478788
ans(sd=.0001)
[1] 1.386604e-06 -6.616540e-05 6.592326e-05 -1.299638e-04 1.322658e-05 -4.515388e-05
[7] -2.809639e-05 -5.719492e-05 1.554319e-04 -1.186992e-04
-----Original Message-----
From: Pascal Oettli [mailto:kridox at ymail.com]
Sent: 4. februar 2013 11:11
To: S?ren H?jsgaard
Cc: r-help at r-project.org
Subject: Re: [R] Modifying a function programmatically
Hi,
Is it what you are looking for?
> ff <- function(a,b,c){a+b+c}
> ff(1,10,12)
[1] 23
> ff(589,2,4)
[1] 595
HTH,
Pascal
Le 04/02/2013 19:00, S?ren H?jsgaard a ?crit :
Dear list
# I have a function
ff <- function(a,b=2,c=4){a+b+c}
# which I programmatically want to modify to a more specialized function in which a is replaced by 1
ff1 <- function(b=2,c=4){1+b+c}
# I do as follows:
vals <- list(a=1)
(expr1 <- as.expression(body(ff)))
expression({
a + b + c
})
(expr2 <- do.call("substitute", list(expr1[[1]], vals))) {
1 + b + c
}
# This "works",
eval(expr2, list(b=10,c=12))
[1] 23
# - but I would like a function. Hence I do:
ll <- alist(b=, c=, eval(expr2))
ff2 <- as.function(ll)
ff2(b=10,c=12)
[1] 23
# BUT I am only half-way where I want to be because the alist(b=, c=, ...)
# requires me plugin the remaining formals by hand. I do:
newformals <-setdiff(names(formals(ff)), names(vals))
vv <- vector("list", length(newformals))
names(vv) <- newformals
(hh <- c(vv, expr2))
$b
NULL
$c
NULL
[[3]]
{
1 + b + c
}
(ff3 <- as.function(hh))
function (b = NULL, c = NULL)
{
1 + b + c
}
ff3(10,12)
[1] 23
# Hence I get the function that returns what I want (given the correct input)
# but the arguments will have default values that I don't want.
# I want to retain the original default values (if any)
ff1()
[1] 7
ff3()
numeric(0)
I have two questions:
1) How to fix the above?
2) Aren't there more elegant alternatives?
Any help would be appreciated.
Regards
S?ren
______________________________________________ R-help at r-project.org 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, Feb 4, 2013 at 5:00 AM, S?ren H?jsgaard <sorenh at math.aau.dk> wrote:
Dear list
# I have a function
ff <- function(a,b=2,c=4){a+b+c}
# which I programmatically want to modify to a more specialized function in which a is replaced by 1
ff1 <- function(b=2,c=4){1+b+c}
This a currying operation. Try: library(functional) ff1 <- Curry(ff, a = 1) # test identical(ff1(2, 4), ff(1, 2, 4)) # TRUE -- Statistics & Software Consulting GKX Group, GKX Associates Inc. tel: 1-877-GKX-GROUP email: ggrothendieck at gmail.com
Dear Gabor,
Thanks for pointing me to this; didn't know the Curry function.
For what it is worth, the two approaches perform somewhat differently in terms of computing time (my "specialize" function is given at the end):
library(functional)
## EXAMPLE 1
ff <- function(a,b=2,c=4){a+b+c}
ff1 <- specialize(ff, vals=list(a=1,bb=123))
ff2 <- Curry(ff, a = 1)
rbenchmark::benchmark(ff1(b=10), ff2(b=10), replications=100000)
test replications elapsed relative user.self sys.self user.child sys.child
1 ff1(b = 10) 100000 0.39 1.000 0.39 0 NA NA
2 ff2(b = 10) 100000 0.81 2.077 0.79 0 NA NA
## EXAMPLE 2
gg <- rnorm
gg1 <- specialize(gg, list(n=10))
gg2 <- Curry(gg, n=1000)
rbenchmark::benchmark(gg1(), gg2(), replications=100000)
test replications elapsed relative user.self sys.self user.child sys.child
1 gg1() 100000 0.53 1.000 0.53 0.00 NA NA
2 gg2() 100000 9.25 17.453 9.22 0.01 NA NA
where
specialize <- function(ff, vals){
expr1 <- as.expression(body(ff))
expr2 <- do.call("substitute", list(expr1[[1]], vals))
gg <- formals(ff)
idx <-match(names(vals), names(gg))
idx <- idx[!is.na(idx)]
if (length(idx)>0){ gg <- gg[-idx]}
as.function(c(gg, expr2))
}
Best regards
S?ren
-----Original Message-----
From: Gabor Grothendieck [mailto:ggrothendieck at gmail.com]
Sent: 4. februar 2013 17:31
To: S?ren H?jsgaard
Cc: r-help at r-project.org
Subject: Re: [R] Modifying a function programmatically
On Mon, Feb 4, 2013 at 5:00 AM, S?ren H?jsgaard <sorenh at math.aau.dk> wrote:
Dear list
# I have a function
ff <- function(a,b=2,c=4){a+b+c}
# which I programmatically want to modify to a more specialized function in which a is replaced by 1
ff1 <- function(b=2,c=4){1+b+c}
This a currying operation. Try: library(functional) ff1 <- Curry(ff, a = 1) # test identical(ff1(2, 4), ff(1, 2, 4)) # TRUE -- Statistics & Software Consulting GKX Group, GKX Associates Inc. tel: 1-877-GKX-GROUP email: ggrothendieck at gmail.com