กำหนดชื่อฟังก์ชันภายในฟังก์ชันนั้น


15

ฉันจะรับชื่อฟังก์ชันในฟังก์ชันที่ไม่ระบุชื่อนั้นได้อย่างไร ด้านล่างฉันคิดว่ามีฟังก์ชั่นหรือกระบวนการในการทำสิ่งนี้เรียกว่าmagical_r_function()และสิ่งที่คาดว่าจะเป็น

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"

คำตอบ:


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

การสาธิต:

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"

ไทเลอร์ฉันไม่รังเกียจแน่นอน (และ GG ก็ดีเหมือนกัน) แต่คุณมีเกณฑ์อะไรในการเลือกคำตอบ
r2evans

คำถามที่ดี. ทั้งทางเลือกที่ยอดเยี่ยม ทั้งคู่ดูเหมือนจะทำงานได้เหมือนกันในการทดสอบของฉัน GG ให้รายละเอียดเพิ่มเติมเล็กน้อย มันยากที่จะตัดสินใจ
Tyler Rinker

เมื่อตรวจสอบเงื่อนไขสุดท้ายของการกำหนดฟังก์ชันให้กับชื่อใหม่อย่างใกล้ชิดยิ่งขึ้นสิ่งนี้สอดคล้องกับการถามเดิม
Tyler Rinker

โปรดอย่าเปลี่ยนความคิดเห็นของฉัน แต่เพียงผู้เดียว! ฉันไม่ได้ wanking และต้องการพนักงาน (แม้ว่าคุณจะมีมากกว่าฉัน) ไม่ฉันแค่อยากรู้ ฉันคิดว่าทั้งสองmatch.callและsys.callเป็นฟังก์ชันพื้นฐานที่ถูกต้องซึ่งมีความแตกต่างกันเล็กน้อยใน "เอฟเฟกต์" และ "ข้อกำหนด" ดังนั้นฉันอยากรู้อยากเห็นที่คุณอาจมีในการเลือกหนึ่งมากกว่าที่อื่น
r2evans

12

ลองsys.call(0)ถ้าเอาท์พุทออบเจ็กต์การโทรนั้นโอเคหรือลดระดับลงหากคุณต้องการให้ชื่อเป็นสตริงอักขระ ด้านล่างนี้เป็นแบบทดสอบสองข้อ sys.call ส่งคืนทั้งชื่อและอาร์กิวเมนต์และ [[1]] เลือกเฉพาะชื่อ

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

g <- function() my_fun()

my_fun()
## [1] "my_fun"

g()
## [1] "my_fun"

ชื่อฟังก์ชั่น

โปรดทราบว่าฟังก์ชั่นไม่ได้มีชื่อจริง สิ่งที่เราถือว่าเป็นชื่อฟังก์ชั่นเป็นเพียงตัวแปรที่เก็บฟังก์ชั่นและไม่ได้เป็นส่วนหนึ่งของฟังก์ชั่น ฟังก์ชั่นประกอบด้วยการขัดแย้งร่างกายและสภาพแวดล้อม - ไม่มีชื่อฟังก์ชั่นในองค์ประกอบเหล่านั้น

ฟังก์ชั่นไม่ระบุชื่อ

นอกจากนี้หนึ่งสามารถมีฟังก์ชั่นที่ไม่ระบุชื่อและสิ่งเหล่านี้อาจส่งคืนผลลัพธ์ที่แปลกเมื่อใช้กับข้างต้น

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

กรณีขอบ

มีบางสถานการณ์ที่มีอยู่โดยเฉพาะอย่างยิ่งที่เกี่ยวข้องกับฟังก์ชั่นที่ไม่ระบุชื่อซึ่งdeparseจะส่งคืนมากกว่าหนึ่งองค์ประกอบดังนั้นหากคุณต้องการที่จะครอบคลุมกรณีขอบดังกล่าวใช้อาร์กิวเมนต์ nlines = 1 เพื่อโต้แย้งหรือใช้ deparse (... ) [[1]] หรือ พูดถึงโดย @Konrad Rudolph โดยใช้ deparse1 ใน 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]])"

อื่น ๆ

จำ หากเหตุผลที่คุณต้องการชื่อฟังก์ชั่นคือการเรียกใช้ฟังก์ชั่นซ้ำแล้วใช้Recall()แทน จากไฟล์ช่วยเหลือ:

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

คำเตือนและหยุดทั้งคู่ออกชื่อฟังก์ชั่นพร้อมกับอาร์กิวเมนต์อะไรก็ตามที่ถูกส่งให้พวกเขาดังนั้นจึงไม่จำเป็นต้องได้รับชื่อฟังก์ชั่นปัจจุบัน

testWarning <- function() warning("X")
testWarning()
## Warning message:
## In testWarning() : X

2
“ edge edge” ของคุณได้รับการแก้ไขอย่างหรูหราใน R 4.0 ผ่านการแนะนำdeparse1ฟังก์ชั่น ฉันเดาว่าเราควรเริ่มใช้สิ่งนั้นแทนdeparseค่าเริ่มต้นเมื่อการยอมรับนั้นสูงพอ
Konrad Rudolph

+1 สำหรับRecallซึ่งฉันรู้สึกว่าเป็นสิ่งที่ OP ต้องการจริงๆ แต่ตัวอย่างของคุณของลำดับฟีโบนักชีไม่ได้จริงๆที่ดีอย่างหนึ่ง: มันมีปัญหาที่คุณมักจะทำซ้ำโทร: สำหรับfib(10), fib(8)เรียกว่า 2 ครั้งรวม (ครั้งโดยfib(10)โดยตรงครั้งโดยfib(9)) fib(7)เรียกว่า 3 ครั้งfib(6)จะเรียกว่า 5 ครั้ง ดูว่าจะเกิดอะไรขึ้น?
Emil Bode

@Emil นี่เป็นสิทธิ์จากหน้าช่วยเหลือของ Recall (ดังที่ระบุไว้ในคำตอบ) ดังนั้นมันจึงแสดงให้เห็นถึงประเด็น หากคุณไม่ชอบที่อื่นคุณสามารถร้องเรียนกับผู้พัฒนา R ได้
G. Grothendieck

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.