Tentukan nama fungsi di dalam fungsi itu

15

Bagaimana saya bisa mendapatkan nama fungsi dalam fungsi non-anonim itu? di bawah ini saya berasumsi ada fungsi atau proses untuk melakukan ini disebut magical_r_function()dan apa yang diharapkan akan dihasilkan.

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
sumber

Jawaban:

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
sumber
Tyler, saya tentu tidak keberatan (dan GG juga bagus), tetapi apa kriteria Anda untuk memilih jawaban mana?
r2evans
Pertanyaan bagus. Keduanya pilihan yang sangat baik. Keduanya tampak bekerja sama dalam tes saya. GG memberikan sedikit lebih detail. Sulit untuk memutuskan.
Tyler Rinker
Setelah memeriksa lebih dekat kondisi terakhir dari penugasan fungsi ke nama baru, yang satu ini lebih dekat dengan yang asli.
Tyler Rinker
Tolong jangan hanya mengubah komentar saya! Saya tidak wanking dan membutuhkan repetisi (meskipun Anda memiliki sedikit lebih banyak daripada saya). Tidak, saya hanya ingin tahu. Saya pikir keduanya match.calldan sys.callfungsi dasar yang valid dengan sedikit perbedaan dalam "efek" dan "persyaratan". Jadi saya ingin tahu wawasan yang mungkin Anda miliki dalam memilih satu dari yang lain.
r2evans
12

Coba sys.call(0)jika output objek panggilan ok atau jelaskan jika Anda hanya ingin nama sebagai string karakter. Di bawah ini adalah beberapa tes ini. sys.call mengembalikan nama dan argumennya dan [[1]] hanya memilih nama.

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

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

Nama fungsi

Perhatikan bahwa fungsi sebenarnya tidak memiliki nama. Apa yang kita anggap sebagai nama fungsi sebenarnya hanya variabel yang memiliki fungsi dan bukan bagian dari fungsi itu sendiri. Fungsi terdiri dari argumen, tubuh, dan lingkungan - tidak ada nama fungsi di antara konstituen tersebut.

Fungsi anonim

Selain itu, orang dapat memiliki fungsi anonim dan ini dapat mengembalikan hasil aneh ketika digunakan dengan di atas.

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

Kasus tepi

Memang ada beberapa situasi, terutama yang melibatkan fungsi anonim, di mana deparseakan mengembalikan lebih dari satu elemen jadi jika Anda ingin menutup kasus tepi tersebut gunakan argumen nlines = 1 untuk menyebarkan atau menggunakan deparse (...) [[1]] atau sebagai disebutkan oleh @Konrad Rudolph dengan menggunakan deparse1 di 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]])"

Lain

Ingat . Jika alasan Anda ingin nama fungsi adalah untuk memanggil fungsi secara rekursif, maka gunakanlah Recall(). Dari file bantuan:

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

peringatan dan berhenti Keduanya mengeluarkan nama fungsi bersama dengan argumen apa pun yang diberikan kepada mereka sehingga tidak perlu untuk mendapatkan nama fungsi saat ini.

testWarning <- function() warning("X")
testWarning()
## Warning message:
## In testWarning() : X
G. Grothendieck
sumber
2
"Kasus tepi" Anda diselesaikan dengan elegan di R 4.0 melalui pengenalan deparse1fungsi. Saya kira kita harus mulai menggunakan itu daripada deparsesecara default, setelah adopsi cukup tinggi.
Konrad Rudolph
+1 untuk Recall, yang saya rasa adalah apa yang benar-benar dibutuhkan OP. Namun, contoh Anda dari deret Fibonacci tidak benar-benar bagus: ia memiliki masalah yang sering Anda ulangi panggilan: karena fib(10), fib(8)disebut 2 kali total (sekali fib(10)secara langsung, sekali oleh fib(9)), fib(7)disebut 3 kali, fib(6)disebut 5 kali. Lihat kemana ini?
Emil Bode
@ Emil, Ini benar dari halaman Panggil bantuan (seperti yang dinyatakan dalam jawaban) sehingga jelas menggambarkan intinya. Jika Anda tidak suka dengan alasan lain, Anda dapat mengeluh kepada pengembang R.
G. Grothendieck
5

Kita juga bisa menggunakan

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

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