2015-04-19 11 views
9

Nếu tôi tạo một hàm như sau:Bạn có thể giải thích rõ hơn về đánh giá lười biếng trong các toán tử hàm R không?

what_is_love <- function(f) { 
    function(...) { 
    cat('f is', f, '\n') 
    } 
} 

Và gọi nó với lapply: funs <- lapply(c('love', 'cherry'), what_is_love)

tôi nhận được kết quả bất ngờ:

> funs[[1]]() 
f is cherry 
> funs[[2]]() 
f is cherry 

Nhưng lưu ý rằng đây không phải là trường hợp khi bạn không sử dụng lapply:

> f1 <- what_is_love('love') 
> f2 <- what_is_love('cherry') 
> f1() 
f is love 
> f2() 
f is cherry 

Điều gì mang lại?

Tôi biết rằng funs <- lapply(c('love', 'cherry'), what_is_love) có thể được viết ra đầy đủ hơn:

params <- c('love', 'cherry') 
out <- vector('list', length(params)) 
for (i in seq_along(params)) { 
    out[[i]] <- what_is_love(params[[i]]) 
} 
out 

Nhưng khi tôi duyệt trong, tôi thấy rằng cả hai chức năng có môi trường riêng của họ:

Browse[1]> out[[1]] 
function(...) { 
    cat('f is', f, '\n') 
    } 
<environment: 0x109508478> 
Browse[1]> out[[2]] 
function(...) { 
    cat('f is', f, '\n') 
    } 
<environment: 0x1094ff750> 

Nhưng trong mỗi người môi trường, f là giống nhau ...

Browse[1]> environment(out[[1]])$f 
[1] "cherry" 
Browse[1]> environment(out[[2]])$f 
[1] "cherry" 

Tôi kno w câu trả lời là "đánh giá lười biếng", nhưng tôi đang tìm kiếm một chút sâu hơn ... làm thế nào để f kết thúc lại được giao trên cả hai môi trường? Trường hợp nào f đến từ đâu? Làm thế nào để đánh giá lười biếng R làm việc dưới mui xe trong ví dụ này?

-

EDIT: Tôi nhận thức được the other question trên đánh giá lười biếng và functionals, nhưng nó chỉ cho biết câu trả lời là "lười biếng đánh giá" mà không giải thích như thế nào đánh giá lười biếng thực sự hoạt động. Tôi đang tìm kiếm chiều sâu hơn.

+0

thể trùng lặp của [Giải thích một đứa lười biếng đánh giá] (http://stackoverflow.com/questions/16129902/explain-a-lazy-evaluation-quirk) – jangorecki

+1

lapply không còn hành vi nào theo cách này trong R-3.2. 0. –

Trả lời

11

Khi bạn làm

what_is_love <- function(f) { 
    function(...) { 
    cat('f is', f, '\n') 
    } 
} 

chức năng bên trong tạo ra một vỏ bọc cho f, nhưng nắm bắt được rằng cho đến khi bạn thực sự sử dụng một biến chuyển cho một chức năng, nó vẫn còn là một "lời hứa" và không phải là thực sự được đánh giá. Nếu bạn muốn "nắm bắt" giá trị hiện tại của f, thì bạn cần bắt buộc đánh giá lời hứa; bạn có thể sử dụng chức năng force() cho điều này.

what_is_love <- function(f) { 
    force(f) 
    function(...) { 
    cat('f is', f, '\n') 
    } 
} 
funs <- lapply(c('love', 'cherry'), what_is_love) 

funs[[1]]() 
# f is love 
funs[[2]]() 
# f is cherry 

Nếu không có force(), f vẫn là lời hứa bên trong cả hai chức năng trong danh sách của bạn. Nó không được đánh giá cho đến khi bạn gọi hàm, và khi bạn gọi hàm mà lời hứa được đánh giá đến giá trị đã biết cuối cùng cho f là "cherry".

Như @MartinMorgran đã chỉ ra, hành vi này đã thay đổi trong R 3.2.0. Từ release notes

chức năng bậc cao như áp dụng các chức năng và giảm() nay buộc đối số cho các chức năng họ áp dụng để loại bỏ tương tác không mong muốn giữa đánh giá lười biếng và chụp biến trong đóng cửa.Điều này giải quyết PR # 16093.

+0

Tuyệt vời, cảm ơn các chi tiết. Bạn sẽ có thể giải thích thêm một chút về cách mà lời hứa R hoạt động dưới mui xe? – peterhurford

+0

Bạn không bao giờ thực sự làm việc với các lời hứa trực tiếp trong mã R vì ngay sau khi bạn chạm vào chúng, chúng sẽ biến mất. Nếu bạn muốn biết chúng được triển khai như thế nào, bạn sẽ phải đọc [R source] (https://github.com/wch/r-source). Có thêm một chút thông tin về họ trong cuộc thảo luận của Hadley về [đánh giá phi tiêu chuẩn] (http://adv-r.had.co.nz/Computing-on-the-language.html) – MrFlick

+0

Bạn cũng có thể quan tâm đến [pryr] (https://github.com/hadley/pryr) gói có chức năng như 'promise_info()' để giúp trích xuất thông tin về lời hứa. – MrFlick

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