2013-04-21 33 views
57

Hadley Wickhams'ın Github hakkındaki kitabı, özellikle this part on lazy evaluation. Orada add/adders fonksiyonları ile tembel değerlendirme sonuçları bir sonuç verir. Let me alıntı Sinirin: Eğer toplayıcının biri diyoruzBir tembel değerlendirmeyi açıklayın

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

tembel ilk kez değerlendirilir x: lapply üretilen ambalajlar veya bir döngü oluştururken

Bu [tembel değerlendirme] önemlidir fonksiyonlar. Bu noktada, döngü tamamlandı ve x x'in son değeri 10'dur. Bu nedenle, toplayıcı işlevlerinin tümü, muhtemelen istediğinizi değil, girişine 10 ekleyecektir! O biraz anlamak görünmüyor

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

ve açıklama asgari vardır: Manuel sorunu değerlendirme düzeltmeleri zorlayarak. Birisi bu özel örneği hazırlayabilir mi ve orada neler olduğunu açıklayabilir mi? "Bu noktada, döngü tamamlandı ve x'in son değeri 10" cümlesiyle özellikle şaşırıyorum. Hangi döngü? Hangi final değeri, nerede? Eksik olduğum bir şey olmalı, ama göremiyorum. Şimdiden çok teşekkürler.

+3

Not aşağıya cevabımı bakın. – jhin

+0

@ jhin'in yorumuyla ilgili yorum: 'lapply() 'son R'de değişirken,' lapply() 'nin olduğu yerde kullanılmak üzere tasarlanmış olan purrr :: map()' fonksiyonu, eski gibi davranıyor. lapply() 'nin kapalı kapılardaki paylaşılan ortamları. Ancak, purrr :: map() 'ın bu“ anachronism ”ına sadık kalmayacağım, çünkü gelecek sürümlerde büyük olasılıkla düzeltilecek. – egnha

+0

@jhin Aslına bakılırsa, hadley'nin öğretisi github'dan direk olarak inşa edilmiştir, bu yüzden R 3.2.0'dan sonra okumak o kadar tuhaftır ki, bu sürüm, eğitimsel tartışmada tembel değerlendirme hakkında tüm bölümü hazırlamıştır: “adders” ile daha fazla bir fark yoktur. 'adders2' çıktıları! –

cevap

34

hedefi:

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

birinci, ikinci vs. Tembel değerlendirme gerçekten toplayıcılar oluşturmak için beklemek R neden olur 2 ekler, girdisinde 1 ekler, add fonksiyonların bir listesini oluşturmak için İşlevleri gerçekten aramaya başlayana kadar işlev görür. Sorun, ilk toplayıcı işlevini oluşturduktan sonra,lapply döngü tarafından 10 değerinde biten, artar. İlk toplayıcı işlevini çağırdığınızda, tembel değerlendirme şimdi işlevi kurar, x değerini alır. Sorun orijinal x birine artık eşit olduğunu, ancak lapply döngünün sonunda değerine nedenle yani 10.

için, tembel değerlendirme lapply döngü tamamlandıktan sonra kadar beklemek tüm toplayıcı fonksiyonları neden olur işlevi gerçekten inşa etmekte. Daha sonra, işlevlerini aynı değerle, yani 10 ile inşa ederler. Hadley'in önerdiği çözüm, x'u doğrudan değerlendirmek, tembel değerlendirme yapmaktan kaçınmak ve doğru fonksiyonları doğru x değerleri ile almaktır.

+4

Tamam, bunu doğru alıp almadığımı görmek için bunu tekrar söyleyeyim. 'Lapply' dediğimiz zaman, R sıralama, tüm 10 toplayıcı işlevinin yapısını hatırlar, ancak x'i henüz değerlendirmez. İlk toplayıcı işlevini çağırdığımızda, R diyor ki, aha, bunun ne olduğunu görelim, x'i bu zaman noktasında zaten olan x'i alır ve ilk adlandırma işlevini 10 + y olarak değerlendirir. Kalan toplayıcı işlevleri için aynı, hepsini tamamen aynı. Muhtemelen kaba bir şekilde koymak, ama bu mantık bu mu? –

+0

Bunun böyle olduğuna inanıyorum. –

+1

@ Maxim.K Evet, tam olarak doğru. – hadley

52

Bu artık R 3.2.0'dan itibaren geçerli değil!

change log karşılık gelen satır okur: bu tür fonksiyonları uygulamak ve yavaş değerlendirme arasında istenmeyen etkileşimlerin ortadan kaldırılması için geçerlidir fonksiyonlara) (Şimdi kuvvet argümanlar azaltmak olarak

yüksek dereceden fonksiyonlar kapanışlarda değişken yakalama .

Ve gerçekten: Bu sorunun cevabı R 3.2.0 itibariyle değiştiğini

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

Büyük bilgi. Beni de şaşırttı ve bunun lapply'yi değiştirdiğini düşündüm. – AllYouCanEat86