2013-04-21 34 views
57

Tôi đang đọc cuốn sách của Hadley Wickhams về Github, cụ thể là this part on lazy evaluation. Ở đó, ông đưa ra một ví dụ về hậu quả của việc đánh giá lười biếng, một phần với chức năng add/adders. Hãy để tôi trích đoạn mà bit:Giải thích một câu hỏi đánh giá lười biếng

này [lười biếng đánh giá] là rất quan trọng khi tạo đóng cửa với lapply hoặc một vòng lặp:

add <- function(x) { 
    function(y) x + y 
} 
adders <- lapply(1:10, add) 
adders[[1]](10) 
adders[[10]](10) 

x là lười biếng đánh giá lần đầu tiên bạn gọi một trong những bộ cộng chức năng. Tại thời điểm này, vòng lặp hoàn tất và giá trị cuối cùng của x là 10. Vì vậy, tất cả các hàm cộng sẽ thêm 10 vào đầu vào của chúng, có thể không phải là những gì bạn muốn! Bằng tay buộc sửa thẩm vấn đề:

add <- function(x) { 
    force(x) 
    function(y) x + y 
} 
adders2 <- lapply(1:10, add) 
adders2[[1]](10) 
adders2[[10]](10) 

Tôi dường như không hiểu rằng chút, và lời giải thích có là tối thiểu. Ai đó có thể vui lòng xây dựng ví dụ cụ thể đó và giải thích điều gì sẽ xảy ra ở đó? Tôi đặc biệt bối rối bởi câu "tại thời điểm này, vòng lặp hoàn tất và giá trị cuối cùng của x là 10". Vòng lặp gì? Giá trị cuối cùng, ở đâu? Phải là một cái gì đó đơn giản tôi đang mất tích, nhưng tôi chỉ không nhìn thấy nó. Cảm ơn rất nhiều trước.

+3

Lưu ý rằng câu trả lời cho câu hỏi này đã thay đổi như của R 3.2.0, xem câu trả lời của tôi dưới đây. – jhin

+0

Bổ sung cho nhận xét của jhin: Trong khi 'lapply()' đã thay đổi trong R gần đây, hàm 'purrr :: map()', được sử dụng ở bất cứ nơi nào 'lapply()', vẫn hoạt động như cũ ' lapply() 'vis-à-vis môi trường chia sẻ của bao đóng. Tuy nhiên, tôi sẽ không dựa vào "lỗi thời" này của 'purrr :: map()' để gắn bó xung quanh, vì nó có thể sẽ được sửa chữa trong các phiên bản sau. – egnha

+0

@jhin Trên thực tế, tôi đoán hướng dẫn của hadley được xây dựng trực tiếp từ github để đọc nó sau khi R 3.2.0 bây giờ khá kì lạ khi bản phát hành đó đưa ra toàn bộ phần về đánh giá lười biếng trong hướng dẫn đó: không có sự khác biệt nào với 'adders' và Kết quả đầu ra 'adders2'! –

Trả lời

34

Mục tiêu của:

adders <- lapply(1:10, function(x) add(x)) 

là tạo ra một danh sách các add chức năng, là người đầu tiên thêm 1 vào đầu vào của nó, thứ hai thêm 2, vv Lazy đánh giá gây R để chờ thực sự tạo ra adders cho đến khi bạn thực sự bắt đầu gọi các hàm. Vấn đề là sau khi tạo hàm adder đầu tiên, x được tăng thêm bởi vòng lặp lapply, kết thúc bằng giá trị 10. Khi bạn gọi hàm adder đầu tiên, đánh giá lười bây giờ xây dựng hàm, nhận giá trị x. Vấn đề là bản gốc x không còn tương đương với một, nhưng với giá trị vào cuối của lapply vòng lặp, tức là 10

Do đó, đánh giá lười biếng gây ra tất cả các chức năng cộng phải đợi cho đến sau khi vòng lặp lapply đã hoàn thành thực sự xây dựng chức năng. Sau đó, họ xây dựng chức năng của họ với cùng một giá trị, tức là 10. Giải pháp Hadley gợi ý là buộc x được đánh giá trực tiếp, tránh đánh giá lười biếng và nhận các hàm chính xác với giá trị x chính xác.

+4

Ok, hãy để tôi thuật lại để xem liệu tôi có đúng không. Khi chúng ta gọi 'lapply', kiểu R nhớ cấu trúc của tất cả 10 hàm cộng, nhưng không đánh giá x. Khi chúng ta gọi hàm adder đầu tiên, R nói, aha, chúng ta hãy xem đó là gì, lấy x, mà đã là 10 tại thời điểm đó từ cuộc gọi lapply, và đánh giá hàm đầu tiên được gọi là hàm adder là 10 + y. Tương tự cho các chức năng của trình bổ sung còn lại, hiển thị chúng giống hệt nhau. Có lẽ là một cách thô lỗ, nhưng đó có phải là logic của nó không? –

+0

Tôi tin rằng đây là trường hợp. –

+1

@ Maxim.K vâng, đó là chính xác. – hadley

52

Điều này không còn đúng với R 3.2.0 nữa!

Dòng tương ứng trong change log đọc:

chức năng bậc cao như áp dụng các chức năng và giảm() bây giờ đối số lực lượng chức năng mà 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à biến chụp trong bao đóng.

Và quả thực:

add <- function(x) { 
    function(y) x + y 
} 
adders <- lapply(1:10, add) 
adders[[1]](10) 
# [1] 11 
adders[[10]](10) 
# [1] 20 
+1

Thông tin tuyệt vời. Tôi cũng bối rối và tôi nghĩ rằng có thể đã tinh chỉnh một cách tinh tế – AllYouCanEat86

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