2017-12-20 104 views
7

Tôi hơi ngạc nhiên bởi hành vi của R trong một trường hợp rất cụ thể. Hãy nói rằng tôi định nghĩa một hàm square trả về bình phương của đối số của nó, như thế này:deparse (replace()) trả về tên hàm bình thường, nhưng mã chức năng khi được gọi bên trong cho vòng lặp

square <- function(x) { return(x^2) } 

Tôi muốn gọi hàm này trong chức năng khác, và tôi cũng muốn hiển thị tên của nó khi tôi làm điều đó. Tôi có thể làm điều đó bằng cách sử dụng deparse(substitute()). Tuy nhiên, hãy xem xét các ví dụ sau:

ds1 <- function(x) { 
    print(deparse(substitute(x))) 
} 

ds1(square) 
# [1] "square" 

Đây là kết quả mong đợi, vì vậy tất cả đều ổn. Tuy nhiên, nếu tôi vượt qua chức năng được bọc trong một danh sách và xử lý nó bằng cách sử dụng vòng lặp for, sau đây sẽ xảy ra:

ds2 <- function(x) { 
    for (y in x) { 
    print(deparse(substitute(y))) 
    } 
} 

ds2(c(square)) 
# [1] "function (x) " "{"    " return(x^2)" "}" 

Ai có thể giải thích cho tôi tại sao điều này xảy ra và làm thế nào tôi có thể ngăn chặn nó xảy ra?

Trả lời

7

Ngay khi bạn sử dụng x bên trong chức năng của mình, nó được đánh giá, vì vậy nó "dừng biểu thức (chưa được đánh giá)" và "bắt đầu là giá trị kết quả của nó (biểu thức được đánh giá)". Để ngăn chặn điều này, bạn phải chụp x trước substitute trước khi sử dụng lần đầu tiên.

Kết quả của substitute là một đối tượng mà bạn có thể truy vấn như thể nó là một danh sách. Vì vậy, bạn có thể sử dụng

x <- substitute(x) 

và sau đó x[[1]] (tên hàm) và x[[2]] và sau (các đối số của hàm)

Vì vậy, công trình này:

ds2 <- function(x) { 
    x <- substitute(x) 
    # you can do `x[[1]]` but you can't use the expression object x in a 
    # for loop. So you have to turn it into a list first 
    for (y in as.list(x)[-1]) { 
     print(deparse(y)) 
    } 
} 
ds2(c(square,sum)) 
## [1] "square" 
## [1] "sum" 
+1

tuyệt vời, cảm ơn. Rõ ràng, thuật ngữ kỹ thuật cho điều này là một 'đối tượng lời hứa'. Trong khi 'x' là một lời hứa, các phần tử của nó (khi được gán cho' y') không phải là lời hứa nữa và do đó 'replace' trả về một giá trị khác. –

Các vấn đề liên quan