สัญญาอยู่ภายใต้การประเมินผล: การอ้างอิงอาร์กิวเมนต์เริ่มต้นซ้ำหรือปัญหาก่อนหน้านี้หรือไม่


143

นี่คือรหัส R ของฉัน ฟังก์ชั่นถูกกำหนดเป็น:

f <- function(x, T) {
  10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}

g <- function(x, T, f=f) {
  exp(-f(x) / T)
}

test <- function(g=g, T=1) { 
  g(1, T)
}

ข้อผิดพลาดในการทำงานคือ:

> test ()
ข้อผิดพลาดในการทดสอบ ():
สัญญาแล้วภายใต้การประเมินผล: การอ้างอิงอาร์กิวเมนต์เริ่มต้นซ้ำหรือปัญหาก่อนหน้านี้?

หากฉันแทนที่คำจำกัดความของfในgนั้นข้อผิดพลาดจะหายไป

ฉันสงสัยว่าข้อผิดพลาดคืออะไร วิธีการแก้ไขถ้าไม่แทนที่คำจำกัดความfในนั้นg? ขอบคุณ!


ปรับปรุง:

ขอบคุณ! สองคำถาม:

(1) ถ้าฟังก์ชั่นtestนั้นเป็นที่ถกเถียงกันfมากขึ้นคุณจะเพิ่มอะไรอีกtest <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) }ไหม ในกรณีที่มี recursions มากขึ้นก็เป็นสิ่งที่ดีและปลอดภัยในการปฏิบัติงานเพิ่มมากขึ้น ?

(2) ถ้าfเป็นข้อโต้แย้งที่ไม่ใช่ฟังก์ชั่นตัวอย่างเช่นg <- function(x, T, f=f){ exp(-f*x/T) }และtest <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) }จะใช้ชื่อเดียวกันสำหรับข้อโต้แย้งทั้งที่เป็นทางการและไม่จริงและเป็นการปฏิบัติที่ดีและปลอดภัยหรืออาจก่อให้เกิดปัญหาที่อาจเกิดขึ้น?

คำตอบ:


159

อาร์กิวเมนต์ที่เป็นทางการของแบบฟอร์มx=xทำให้สิ่งนี้ กำจัดสองตัวอย่างที่เกิดขึ้นที่เราได้รับ:

f <- function(x, T) {
   10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80 
}

g <- function(x, T, f. = f) {  ## 1. note f.
   exp(-f.(x)/T) 
}

test<- function(g. = g, T = 1) {  ## 2. note g.
   g.(1,T) 
}

test()
## [1] 8.560335e-37

2
ขอบคุณ! คำถามสองข้อ (1) ถ้าการทดสอบฟังก์ชั่นเพิ่มเติมใช้อาร์กิวเมนต์สำหรับfคุณจะต้องเพิ่มการทดสอบ <- ฟังก์ชั่น (g. = g, T = 1, f .. = f) {g. (1, T, f) = f .. )} ? ในกรณีที่มี recursions มากขึ้นก็เป็นสิ่งที่ดีและปลอดภัยในการปฏิบัติงานเพิ่มมากขึ้น ? (2) ถ้าfเป็นอาร์กิวเมนต์ที่ไม่ใช่ฟังก์ชันตัวอย่างเช่นg <- ฟังก์ชัน (x, T, f = f) {exp (-f x / T)} * และทดสอบ <- ฟังก์ชัน (g. = g, T = 1, f = f) {g. (1, T, f = f.)} , จะใช้ชื่อเดียวกันสำหรับข้อโต้แย้งทั้งที่เป็นทางการและไม่จริงและเป็นวิธีปฏิบัติที่ดีและปลอดภัยหรืออาจก่อให้เกิดปัญหาที่อาจเกิดขึ้น?
ทิม

16
ทางออกอื่น ๆ ฉันผ่านการขัดแย้งบางอย่างค่อนข้างลึกลงห่วงโซ่ของฟังก์ชั่น (ประมาณ 5 ระดับ) .....cumbersomeและการแก้ปัญหานี้จะกลายเป็น :)
Roman Luštrik

2
@ RomanLuštrikหากคุณผ่านการขัดแย้งและคุณสามารถละเว้นบางอย่างได้อย่างปลอดภัยแล้วดูที่การใช้รูปไข่...หรือรายการที่จะผ่านการขัดแย้งลงโซ่ฟังก์ชั่น มันมีความยืดหยุ่นมากขึ้น (สำหรับคนดีและคนป่วย) มากกว่าทุกสิ่งที่กำหนดไว้ล่วงหน้า คุณอาจต้องเพิ่มการตรวจสอบเพื่อให้แน่ใจว่าอาร์กิวเมนต์ดั้งเดิมของคุณในรูปไข่ (หรือรายการ) มีเหตุผล
russellpierce

2
อีกตัวเลือกหนึ่งที่นี่คือการอย่างชัดเจนพยายามที่จะหาข้อโต้แย้งในกรอบผู้ปกครองผ่านอุบัติเหตุบังคับของสัญญาที่ใช้งาน - get("f", envir = parent.frame())เช่น
Kevin Ushey

1
ข้อกำหนดเพียงอย่างเดียวคือคุณไม่ได้ใช้ชื่อเดียวกันทางด้านซ้ายและด้านขวา นอกเหนือจากนั้นมันเป็นสไตล์
G. Grothendieck

13

หากคุณระบุบริบทการประเมินผลอาร์กิวเมนต์คุณหลีกเลี่ยงปัญหาชื่อเดียวกัน:

f <- function(x) {
  10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}
g <- function(x, t=1, f=parent.frame()$f) {
  exp(-f(x) / t)
}
test <- function(g=parent.frame()$g, t=1) { 
  g(1,t)
}
test()
[1] 8.560335e-37

2
นี่เป็นวิธีที่ดีกว่าฉันคิดว่าระบุสภาพแวดล้อมที่ชัดเจนยิ่งขึ้น
cloudscomputes

1

ฉันชอบคำตอบG. Grothendieckแต่ฉันสงสัยว่ามันง่ายกว่าในกรณีของคุณที่จะไม่รวมชื่อฟังก์ชันในพารามิเตอร์ของฟังก์ชันเช่นนี้

f <- function(x, T) {
  10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80 
}
g <- function(x, T) {
  exp(-f(x)/T) 
}
test<- function(T = 1) {
  g(1,T)
}
test()
## [1] 8.560335e-37

1

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

สิ่งนี้ไม่ทำงาน:

x = 4
my.function <- function(x = x){} 
my.function() # recursive error!

แต่มันใช้งานได้:

x = 4
my.function <- function(x){} 
my.function(x = x) # works fine!

ฟังก์ชันอาร์กิวเมนต์มีอยู่ในสภาพแวดล้อมท้องถิ่นของตนเอง

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

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

my.function <- function(x, two.x = 2 * x){}

นี่คือเหตุผลที่คุณไม่สามารถกำหนดฟังก์ชันได้my.function <- function(x = x){}แต่คุณสามารถเรียกใช้ฟังก์ชันmy.function(x = x)ได้ เมื่อคุณกำหนดฟังก์ชั่น R จะสับสนเพราะพบอาร์กิวเมนต์x =เป็นค่าโลคัลของxแต่เมื่อคุณเรียกใช้ฟังก์ชัน R พบx = 4ในสภาพแวดล้อมท้องถิ่นที่คุณกำลังโทรหา

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

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