lời hứa đã được đánh giá: tham chiếu đối số mặc định đệ quy hoặc các vấn đề trước đó?


143

Đây là mã R của tôi. Các chức năng được định nghĩa là:

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)
}

Lỗi chạy là:

> test ()
Error in test ():
lời hứa đã được đánh giá: tham chiếu đối số mặc định đệ quy hoặc các vấn đề trước đó?

Nếu tôi thay thế định nghĩa ftrong đó g, thì lỗi sẽ biến mất.

Tôi đã tự hỏi những gì là lỗi? Làm thế nào để sửa nó nếu không thay thế định nghĩa ftrong đó g? Cảm ơn!


Cập nhật:

Cảm ơn! Hai câu hỏi:

(1) nếu chức năng testtiếp tục lấy một đối số cho f, bạn sẽ thêm một cái gì đó như thế test <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) }nào? Trong trường hợp có nhiều thu hồi hơn, nó là một thực hành tốt và an toàn thêm nhiều hơn . ?

(2) nếu flà một đối số không có chức năng, ví dụ g <- function(x, T, f=f){ exp(-f*x/T) }test <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) }, sẽ sử dụng cùng tên cho cả đối số phi chức năng chính thức và thực tế, một thực tiễn tốt và an toàn hay nó có thể gây ra một số rắc rối tiềm ẩn?

Câu trả lời:


159

Lập luận chính thức của hình thức x=xgây ra điều này. Loại bỏ hai trường hợp chúng xảy ra:

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
Cảm ơn! Hai câu hỏi (1) nếu kiểm tra chức năng tiếp tục lấy một đối số cho f , bạn sẽ thêm một cái gì đó như kiểm tra <- function (g. = G, T = 1, f .. = f) {g. (1, T, f. = f ..)} ? Trong trường hợp có nhiều thu hồi hơn, nó là một thực hành tốt và an toàn thêm nhiều hơn . ? (2) nếu f là đối số không có chức năng, ví dụ g <- function (x, T, f = f) {exp (-f x / T)} * và kiểm tra <- function (g. = G, T = 1, f = f) {g. (1, T, f = f.)} , Sẽ sử dụng cùng tên cho cả đối số phi chức năng chính thức và thực tế, một thực tiễn tốt và an toàn hay nó có thể gây ra một số rắc rối tiềm ẩn?
Tim

16
Bất kỳ giải pháp nào khác? Tôi đang chuyển một số đối số khá sâu xuống chuỗi chức năng (khoảng 5 cấp độ) và giải pháp này có thể trở thành .....cumbersome. :)
Roman Luštrik

2
@ RomanLuštrik Nếu bạn chuyển các đối số xuống và bạn có thể bỏ qua một số trong số chúng một cách an toàn, thì hãy xem xét bằng cách sử dụng dấu chấm lửng ...hoặc danh sách để chuyển các đối số xuống chuỗi chức năng. Nó linh hoạt hơn nhiều (tốt và xấu) so với việc xác định trước mọi thứ. Cuối cùng, bạn có thể cần thêm một số kiểm tra để đảm bảo các đối số ban đầu của bạn trong dấu chấm lửng (hoặc danh sách) là hợp lý.
russellpierce

2
Một tùy chọn khác ở đây là rõ ràng cố gắng tìm ra lý lẽ trong một khung phụ huynh, bỏ qua tình cờ buộc của lời hứa tích cực - ví dụ get("f", envir = parent.frame()).
Kevin Ushey

1
Yêu cầu duy nhất là bạn không sử dụng cùng tên ở phía bên trái và bên phải. Khác hơn đó chỉ là phong cách.
G. Grothendieck

13

Nếu bạn đặc biệt bối cảnh đánh giá đối số, bạn sẽ tránh được vấn đề cùng tên:

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
Đây là một cách tốt hơn, tôi nghĩ chỉ định môi trường rõ ràng hơn
đám mây

1

Tôi thích câu trả lời của G. Grothendieck , nhưng tôi đã tự hỏi rằng trong trường hợp của bạn đơn giản hơn là không bao gồm tên hàm trong các tham số của hàm, như thế này:

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

Như đã đề cập, vấn đề xuất phát từ việc có một đối số hàm được định nghĩa là chính nó. Tuy nhiên, tôi muốn thêm một lời giải thích tại sao đây là một vấn đề bởi vì sự hiểu biết đã đưa tôi đến một cách dễ dàng hơn (đối với tôi) để tránh vấn đề: chỉ cần xác định đối số trong cuộc gọi thay vì định nghĩa.

Điều này không hoạt động:

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

nhưng điều này không hoạt động:

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

Đối số chức năng tồn tại trong môi trường địa phương của riêng họ.

R tìm kiếm các biến đầu tiên trong môi trường địa phương, sau đó trong môi trường toàn cầu. Điều này giống như cách bên trong một hàm có thể có cùng tên với một biến trong môi trường toàn cầu và R sẽ sử dụng định nghĩa cục bộ.

Có các định nghĩa đối số hàm tạo thành môi trường cục bộ của riêng chúng là lý do tại sao bạn có thể có các giá trị đối số mặc định dựa trên các giá trị đối số khác, như

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

Vì vậy, đây là lý do tại sao bạn không thể xác định hàm như my.function <- function(x = x){}nhưng bạn có thể GỌI hàm bằng cách sử dụng my.function(x = x). Khi bạn xác định hàm, R bị nhầm lẫn vì nó tìm thấy đối số x =là giá trị cục bộ của x, nhưng khi bạn gọi hàm R tìm thấy x = 4trong môi trường cục bộ mà bạn đang gọi.

Vì vậy, ngoài việc sửa lỗi bằng cách thay đổi tên đối số hoặc chỉ định rõ ràng môi trường như được đề cập trong các câu trả lời khác, bạn cũng có thể chỉ định rằng x=xkhi bạn gọi hàm thay vì khi bạn xác định nó. Đối với tôi, chỉ định rằng x=xtrong cuộc gọi là giải pháp tốt nhất, vì nó không liên quan đến cú pháp bổ sung hoặc tích lũy ngày càng nhiều tên biến.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.