Determinar o nome da função nessa função

15

Como posso obter o nome da função nessa função não anônima? abaixo, presumo que exista uma função ou processo para fazer isso chamado magical_r_function()e quais seriam as saídas esperadas.

my_fun <- function(){
      magical_r_function()
}
my_fun()
## [1] "my_fun"


foo_bar <- function(){
      magical_r_function()
}
foo_bar()
## [1] "foo_bar"

ballyhoo <- function(){
    foo_bar()
}
ballyhoo()
## [1] "foo_bar"

tom_foolery <- foo_bar
tom_foolery()
## [1] "tom_foolery"
Tyler Rinker
fonte

Respostas:

18
as.character(match.call()[[1]])

Demo:

my_fun <- function(){
  as.character(match.call()[[1]])
}
my_fun()
# [1] "my_fun"
foo_bar <- function(){
  as.character(match.call()[[1]])
}
foo_bar()
# [1] "foo_bar"
ballyhoo <- function(){
  foo_bar()
}
ballyhoo()
# [1] "foo_bar"
tom_foolery <- foo_bar
tom_foolery()
# [1] "tom_foolery"
r2evans
fonte
Tyler, eu certamente não me importo (e o GG também é bom), mas qual foi o seu critério para qual resposta escolher?
r2evans 28/04
Boa pergunta. Ambas as excelentes opções. Ambos pareciam funcionar da mesma forma nos meus testes. Os GG forneceram um pouco mais de detalhes. Foi difícil decidir.
Tyler Rinker 28/04
Após uma inspeção mais minuciosa, a última condição de atribuir uma função a um novo nome, esta se alinha mais com a solicitação original.
Tyler Rinker 28/04
Por favor, não mude apenas no meu comentário! Não estou me masturbando e precisando de representantes (embora vocês tenham um pouco mais do que eu). Não, eu estava apenas curioso. Eu acho que ambos match.calle sys.callsão funções básicas válidas com pouca diferença em "efeito" e "requisitos". Então, eu estava curioso para saber o que você pode ter ao preferir um ao outro.
r2evans 28/04
12

Tente sys.call(0)se a saída de um objeto de chamada está ok ou remova-a se você quiser apenas o nome como uma sequência de caracteres. Abaixo estão alguns testes disso. sys.call retorna o nome e os argumentos e o [[1]] seleciona apenas o nome.

my_fun <- function() deparse(sys.call(0)[[1]])

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

Nomes de funções

Observe que as funções não têm nomes. O que consideramos nomes de funções são na verdade apenas variáveis ​​que mantêm a função e não fazem parte da própria função. Uma função consiste em argumentos, corpo e ambiente - não há nome de função entre esses constituintes.

Funções anônimas

Além disso, pode-se ter funções anônimas e elas podem retornar resultados estranhos quando usadas com as opções acima.

sapply(1:3, function(x) deparse(sys.call(0)[[1]]))
## [1] "FUN" "FUN" "FUN"

Casos de borda

Existem algumas situações, particularmente envolvendo funções anônimas, em deparseque retornará mais de um elemento; portanto, se você quiser cobrir esses casos de borda, use o argumento nlines = 1 para separar ou use deparse (...) [[1]] ou como mencionado por @Konrad Rudolph usando deparse1 no R 4.0.0.

Map(function(x) deparse(sys.call(0)[[1]], nlines = 1), 1:2)
## [[1]]
## [1] "function (x) "
## 
## [[2]]
## [1] "function (x) "

Map(function(x) deparse(sys.call(0)[[1]]), 1:2)  # without nlines=1
## [[1]]
## [1] "function (x) "             "deparse(sys.call(0)[[1]])"
##
## [[2]]
## [1] "function (x) "             "deparse(sys.call(0)[[1]])"

De outros

Lembre-se . Se o motivo pelo qual você deseja que o nome da função seja chamar recursivamente a função, use-o Recall(). No arquivo de ajuda:

fib <- function(n)
   if(n<=2) { if(n>=0) 1 else 0 } else Recall(n-1) + Recall(n-2)
fib(4)
## [1] 3

aviso e parada Ambos emitem o nome da função, juntamente com qualquer argumento que lhes seja passado, para que não seja necessário obter o nome atual da função.

testWarning <- function() warning("X")
testWarning()
## Warning message:
## In testWarning() : X
G. Grothendieck
fonte
2
O seu “case de borda” é resolvido com elegância no R 4.0 através da introdução da deparse1função. Suponho que devemos começar a usá-lo em vez de deparsepor padrão, uma vez que a adoção seja alta o suficiente.
Konrad Rudolph
+1 para Recall, o que considero ser o que o OP estava realmente precisando. No entanto, seu exemplo da sequência de Fibonacci não é realmente bom: ele tem o problema de repetir frequentemente as chamadas: pois fib(10), fib(8)é chamado 2 vezes no total (uma vez fib(10)diretamente, uma vez por fib(9)), fib(7)é chamado 3 vezes, fib(6)é chamado 5 vezes. Veja para onde isso está indo?
Emil Bode
@ Emil, isso está diretamente na página de ajuda da Recall (como indicado na resposta), portanto, certamente ilustra o ponto. Se você não gostar por outros motivos, pode reclamar com os desenvolvedores do R.
G. Grothendieck
5

Também podemos usar

my_fun <- function(){
  as.character(as.list(sys.calls()[[1]])[[1]])
 }

my_fun()
#[1] "my_fun"
akrun
fonte