Tembel değerlendirmenin nasıl çalıştığını yeni öğrendim ve merak ettim: Şu anda üretilen her yazılımda tembel değerlendirme neden uygulanmıyor? Neden hala istekli değerlendirme kullanıyorsunuz?
Tembel değerlendirmenin nasıl çalıştığını yeni öğrendim ve merak ettim: Şu anda üretilen her yazılımda tembel değerlendirme neden uygulanmıyor? Neden hala istekli değerlendirme kullanıyorsunuz?
Yanıtlar:
Tembel değerlendirme, genel olarak kitap tutmayı gerektirir - henüz değerlendirilip değerlendirilmediğini bilmek zorundasınız. İstekli değerlendirme her zaman değerlendirilir, bu nedenle bilmek zorunda değilsiniz. Bu özellikle eşzamanlı bağlamlarda geçerlidir.
İkincisi, istekli değerlendirmeyi tembel değerlendirmeye dönüştürmek, daha sonra çağrılacak bir fonksiyon nesnesine paketlemek yoluyla önemsizdir .
Üçüncüsü, tembel değerlendirme, kontrol kaybı anlamına gelir. Ya bir diskten dosya okumayı temkinli olarak değerlendirirsem? Ya da zaman alıyor? Bu kabul edilebilir değil.
İstekli değerlendirme daha verimli ve daha kontrol edilebilir olabilir ve önemsiz bir şekilde tembel değerlendirmeye dönüştürülür. Neden tembel bir değerlendirme istiyorsun?
readFile
olduğunu tam olarak neye ihtiyacım. Ayrıca, tembelden istekli değerlendirmeye dönüşüm de aynı derecede önemsiz.
head [1 ..]
Size hevesle değerlendirilmiş bir saf dilde ne verir, çünkü Haskell'de verdiği gibi 1
?
Temelde tembel kod ve durum kötü bir şekilde karışabiliyor ve bazı hataları bulmakta zorlanabiliyor. Bağımlı bir nesnenin durumu değişirse tembel nesnenizin değeri değerlendirildiğinde yanlış olabilir. Programcının durumun uygun olduğunu bildiği zaman tembellenecek nesneyi açıkça kodlamasını sağlamak çok daha iyidir.
Bir yandan, Haskell her şey için Tembel değerlendirme kullanır. Bu mümkündür, çünkü işlevsel bir dildir ve durum kullanmaz (açıkça işaretlendikleri istisnai durumlar hariç)
set!
tembel bir Scheme tercümanında kullanılmasıyla ilgili olduğunu düşünüyorum . > :(
Tembel değerlendirme her zaman daha iyi değildir.
Tembel değerlendirmenin performans yararları büyük olabilir, ancak istekli ortamlardaki gereksiz değerlendirmelerin çoğundan kaçınmak zor değildir - kesinlikle tembel, kolay ve eksiksiz hale getirir, ancak nadiren kodda gereksiz bir değerlendirme büyük bir problemdir.
Tembel değerlendirme ile ilgili iyi bir şey, daha net bir kod yazmanıza izin vermesidir; sonsuz doğal sayılar listesini filtreleyerek ve bu listenin 10. elemanını alarak 10. sırada olmak, ilerlemenin en özlü ve net yollarından biridir: (sözde kod)
let numbers = [1,2...]
fun is_prime x = none (map (y-> x mod y == 0) [2..x-1])
let primes = filter is_prime numbers
let tenth_prime = first (take primes 10)
Olayları tembel olmadan bu kadar kesin bir şekilde ifade etmenin oldukça zor olacağına inanıyorum.
Ancak tembellik her şeyin cevabı değil. Başlangıç olarak, tembellik devletin varlığında şeffaf bir şekilde uygulanamaz ve ben durumsallığın otomatik olarak algılanamayacağına inanıyorum (devletin oldukça açık olduğu durumlarda Haskell dediğiniz sürece). Bu nedenle, çoğu dilde tembelliğin elle yapılması gerekir, bu da işleri daha az net hale getirir ve böylece tembel değerlendirmenin en büyük faydalarından birini ortadan kaldırır.
Ayrıca, tembellik, değerlendirilmeyen ifadeleri çevrede tutmanın önemli bir ek yükünü gerektirdiğinden performansın sakıncaları vardır; depolamayı kullanıyorlar ve basit değerlerden daha yavaş çalışıyorlar. Eğer tembel sürümü köpek yavaş olduğu için istekli-ify kodu bilmek zorunda nadir değildir ve performans hakkında neden bazen zor.
Gerçekleşme eğiliminde olduğu gibi, mutlak en iyi strateji yoktur. Sınırsız veri yapıları veya kullanmanıza izin verdiği diğer stratejilerden yararlanarak daha iyi kod yazabiliyorsanız Tembellik harikadır ancak istekliyi optimize etmek daha kolay olabilir.
İşte istekli ve tembel değerlendirmenin artıları ve eksileriyle ilgili kısa bir karşılaştırma:
İstekli değerlendirme:
Gereksiz yere değer biçen şeylerin potansiyel yükü.
Engelsiz, hızlı değerlendirme.
Tembel değerlendirme:
Gereksiz değerlendirme yok.
Defter tutma, bir değerin her kullanımında genel giderler.
Yani, asla değerlendirilmemesi gereken birçok ifadeniz varsa, tembel olmak iyidir; Henüz değerlendirilmeniz gerekmeyen bir ifadeniz yoksa, tembel saftır.
Şimdi, gerçek dünya yazılım bir göz atalım: Nasıl fonksiyonların birçoğunu siz do yazma o değil tüm argümanları değerlendirmesini gerektirir? Özellikle sadece bir şeyi yapan modern kısa fonksiyonlarla, fonksiyonların oranı bu kategoriye girme oranı çok düşüktür. Bu nedenle, tembel değerlendirme, çoğu zaman genel olarak bir şeyleri kurtarma şansı olmadan muhasebe işini yükler.
Sonuç olarak, tembel değerlendirme ortalama olarak ortalama ödeme yapmaz, istekli değerlendirme modern koda daha uygun olur.
@DeadMG'nin belirttiği gibi Tembel değerlendirme, kitap tutmanın genel giderini gerektirir. Bu istekli değerlendirmesine göre pahalı olabilir. Bu ifadeyi göz önünde bulundurun:
i = (243 * 414 + 6562 / 435.0 ) ^ 0.5 ** 3
Bu hesaplamak için biraz hesaplama gerektirecektir. Eğer tembel değerlendirme kullanıyorsam, o zaman her kullanmamda değerlendirilip değerlendirilmediğini kontrol etmem gerekir. Bu, yoğun olarak kullanılan sıkı bir halkanın içindeyse, ek yük önemli ölçüde artar, ancak faydası yoktur.
İstekli değerlendirme ve iyi bir derleyici ile formül derleme zamanında hesaplanır. Çoğu optimize edici, ödevi, uygunsa oluştuğu herhangi bir döngüden çıkarır.
Tembel değerlendirme, nadiren erişilecek ve alınması gereken yüksek bir ek yükü olan veri yükleme için en uygun yöntemdir. Bu nedenle, çekirdek işlevsellikten daha fazla durumlarda kenar kesmek daha uygundur.
Genelde, sık erişilen şeyleri mümkün olduğunca erken değerlendirmek iyi bir uygulamadır. Tembel değerlendirme bu uygulamayla çalışmaz. Bir şeye daima erişecekseniz, tüm tembel değerlendirmeler yapılacaktır. Tembel değerlendirme kullanmanın maliyet / faydası, erişilen öğeye erişilme olasılığının azalmasıyla azalır.
Daima tembel değerlendirme kullanmak, erken optimizasyon anlamına da gelir. Bu, genellikle aksi takdirde olabilecek çok daha karmaşık ve pahalı olan kodla sonuçlanan kötü bir uygulamadır. Ne yazık ki, erken optimizasyon genellikle daha basit koddan daha yavaş performans gösteren kodla sonuçlanır. Optimizasyonun etkisini ölçebilinceye kadar, kodunuzu optimize etmek kötü bir fikirdir.
Erken optimizasyondan kaçınmak, iyi kodlama uygulamalarıyla çakışmaz. İyi uygulamalar uygulanmadıysa, ilk optimizasyonlar hesaplamaları döngülerden çıkarmak gibi iyi kodlama uygulamalarını uygulamaktan oluşabilir.
Değerini belirlemek için bir ifadeyi tam olarak değerlendirmek zorunda kalırsak, tembel değerlendirme dezavantaj olabilir. Biz boole değerlerin uzun bir liste olduğunu varsayalım ve biz öğrenmek isteyen tüm bunlardan doğrudur:
[True, True, True, ... False]
Bunu yapabilmek için listedeki her unsura bakmalıyız, ne olursa olsun, bu nedenle değerlendirmeyi tembel kestirme imkanı yoktur. Listedeki tüm boole değerlerinin doğru olup olmadığını belirlemek için bir katlama kullanabiliriz. Tembel değerlendirme kullanan bir katlanma hakkı kullanırsak, tembel değerlendirmenin faydalarından hiçbirini alamayız, çünkü listedeki her öğeye bakmak zorundayız:
foldr (&&) True [True, True, True, ... False]
> 0.27 secs
Bu durumda bir kat hakkı, tembel bir değerlendirme yapmayan katı bir kattan çok daha yavaş olacaktır:
foldl' (&&) True [True, True, True, ... False]
> 0.09 secs
Bunun nedeni, sola doğru katlamanın kuyruk özyinelemesini kullanmasıdır; bu, geri dönüş değerini biriktirdiği ve büyük bir işlem zincirini biriktirmediği ve hafızada saklamadığı anlamına gelir. Bu, tembel katlama sağından çok daha hızlıdır, çünkü her iki fonksiyonun da tüm listeye bakması gerekir ve katlama hakkı kuyruk özyineleme kullanamaz. Yani, mesele şu ki, eldeki görev için en iyisini kullanın.