russellpierce
russellpierce

Reputation: 4711

Accessing the function that is being called from within the function

Within a function, how can we reliably return an object that contains the function itself?

For example with:

functionBuilder <- function(wordToSay) {
  function(otherWordToSay) {
    print(wordToSay)
    print(otherWordToSay)
    get(as.character(match.call()[[1]]))
  }
}

I can build a function like so:

functionToRun <- functionBuilder("hello nested world")

... and run it ...

functionToRun("A")
#[1] "hello nested world"
#[1] "A"
#
#function(otherWordToSay) {
#        print(wordToSay)
#        print(otherWordToSay)
#        get(as.character(match.call()[[1]]))
#      }
#<environment: 0x1e313678>

... as you can see functionToRun returns itself. However, this approach appears to break if I call functionToRun via sapply:

> sapply(LETTERS, functionToRun)
#[1] "hello nested world"
#[1] "A"
#Error in get(as.character(match.call()[[1]])) : object 'FUN' not found

I can see that this is because the actual call when using sapply is FUN but that FUN doesn't exist at pos = -1 (the default for get). Code that works in that position looks like:

get(as.character(match.call()[[1]]),envir = sys.frame(sys.parent()))

But that same code fails if the function hasn't been called via sapply because sys.frame(sys.parent())) goes too far back and ends up referring to R_GlobalEnv.

From the documentation (R 3.2.2) I'd have expected dynGet to perhaps solve the issue of only going as far back in the stack as needed. Although this works for an sapply call of the function, it fails when the function is called on its own. (Besides, it is marked as 'somewhat experimental'). Inversely getAnywhere seems promising, but doesn't seem to work for the sapply called function.

Is there a reliable way to return the function that is currently being processed, i.e. works for both a bare and sapply wrapped function call?

What I'm doing right now is wrapping the attempt to grab the function in a tryCatch; but I'm a little uncertain whether I can trust that get(as.character(match.call()[[1]]),envir = sys.frame(sys.parent())) will work in all wrapping cases (not just sapply). So, I'm looking for a more reasonable way to approach this problem.

Potentially Related Questions:

Upvotes: 1

Views: 73

Answers (1)

Roland
Roland

Reputation: 132989

I can't guarantee that this will work in all cases, but it looks okay:

fun <- function(x) {
  print(x)
  y <- exp(x)
  print(y)
  sys.function(0)
}

fun(1)
# [1] 1
# [1] 2.718282
# function(x) {
#   print(x)
#   y <- exp(x)
#   print(y)
#   sys.function(0)
# }
lapply(1:5, fun)[[3]]
# [1] 1
# [1] 2.718282
# [1] 2
# [1] 7.389056
# [1] 3
# [1] 20.08554
# [1] 4
# [1] 54.59815
# [1] 5
# [1] 148.4132
# function(x) {
#   print(x)
#   y <- exp(x)
#   print(y)
#   sys.function(0)
# }

Of course, I don't understand what you need this for.

Upvotes: 1

Related Questions