Pass function name as argument in mapply?
Asked Answered
E

2

5

I would like to pass a function name as an argument in mapply:

f2 <- function(a, b) a + b^2
f <- function(a, b, func) func(a, b)
f(1, 3, f2)  ## returns 10
mapply(f2,  1:2,  3)  ## returns [1] 10 11
mapply(function(a, b) f(a, b, f2), 1:2,  3) ## returns [1] 10 11
mapply(f,  1:2,  3,  f2)  ## fails

The final mapply call generates the error

Error in dots[[3L]][[1L]] : object of type 'closure' is not subsettable

Is there any way to do this?

Earsplitting answered 25/10, 2019 at 15:8 Comment(0)
L
6

mapply assumes you want to iterate over all the vectors you pass after the first function. But you want to use the same value of f2 for every iteration. You can do that useing the MoreArgs= parameter

mapply(f,  1:2,  3,  MoreArgs=list(func=f2))

You don't have the same problem with the 3 because R will perform vector recycling to expand 3 to c(3,3) to match the same length as c(1,2). Functions in R don't have the same implicit recycling behaviors. But if you want the value to always stay the same, it's better to put it in the MoreArgs parameter

Lomeli answered 25/10, 2019 at 15:12 Comment(2)
Perfect! R obviously knows that f2 is a particular object, namely a function. Where would I look for an explanation of this behavior wrt functions? For example, I can have a list of functions, but I'm not allowed (I understand now) to have a dataframe with a function column.Earsplitting
It's the difference between where R want's an atomic vector or "primitive" types and places where you can have a more general list. Technically you can kind of have functions in a data.frame but they have to be in "list columns". Like you can do x <- data.frame(a=1:2); x$b <- list(mean, sum). But that would mess up things like write.table because you can't write the function to text. Functions are one of the few things that don't behave implicitly like a vector or list without some wrapping.Lomeli
E
0

1) Wrap the function in a list:

mapply(f,  1:2,  3,  list(f2))
## [1] 10 11

2) Typically functions that have function arguments use match.fun so that one can pass either the function or a character string containing its name. For example, mapply itself does that so the above line of code could equally be written as: mapply("f", 1:2, 3, list(f2)) . If f were written that way then we could simply specify the name of f2 as a character string, namely "f2" .

f <- function(a, b, func) {
  func <- match.fun(func)
  func(a, b)
}

mapply(f,  1:2,  3,  "f2")
## [1] 10 11
Encincture answered 25/10, 2019 at 16:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.