Tembel değerlendirme neden her yerde kullanılmıyor?


32

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?


2
Değişken durumu ve tembel değerlendirmeyi karıştırırsanız neler olabileceğine bir örnek. alicebobandmallory.com/articles/2011/01/01/…
Jonas Elfström

2
@ JonasElfström: Lütfen değişken durumları olası uygulamalarından biriyle karıştırmayın. Değişken durum sonsuz, tembel bir değer akışı kullanılarak uygulanabilir. Öyleyse değişken değişkenler probleminiz yok.
Giorgio

Zorunlu programlama dillerinde "tembel değerlendirme", programcıdan bilinçli bir çaba gerektirir. Zorunlu dillerde genel programlama bunu kolaylaştırdı, ancak asla şeffaf olmayacak. Sorunun diğer tarafına verilen cevap başka bir soruyu ortaya çıkarmaktadır: "Neden işlevsel programlama dilleri her yerde kullanılmıyor?"
rwong

2
İşlevsel programlama dilleri her yerde kullanılmaz, aynı nedenle vidalar üzerinde çekiç kullanmayız, her sorun işlevsel bir giriş -> çıkış biçiminde kolayca ifade edilemez, örneğin GUI zorunlu bir şekilde ifade edilmek için daha uygundur. .
ALXGTV

Ayrıca, iki işlevsel programlama dili sınıfı (veya en azından her ikisi de işlevsel olduğunu iddia eder), zorunlu işlevsel diller, örneğin Clojure, Scala ve bildirici, örneğin Haskell, OCaml vardır.
ALXGTV

Yanıtlar:


38

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?


10
Lazily diskten bir dosya okunurken aslında gerçekten temiz - benim basit programlar ve scriptler çoğu için, Haskell readFileolduğunu tam olarak neye ihtiyacım. Ayrıca, tembelden istekli değerlendirmeye dönüşüm de aynı derecede önemsiz.
Tikhon Jelvis

3
Son paragraf hariç, sizinle aynı fikirdeyim. Tembel değerlendirme, zincirleme bir işlem olduğunda daha etkilidir ve verilere gerçekten ihtiyacınız olduğunda daha fazla kontrol sahibi olabilir
texasbruce

4
Functor yasaları sizinle "kontrolün kaybı" hakkında bir şeyler söylemek ister. Değişmez veri türleri üzerinde çalışan saf fonksiyonlar yazarsanız, tembel değerlendirme bir nimettir. Haskell gibi diller temelde tembellik kavramını temel alır. Bazı dillerde, özellikle "güvensiz" kodla karıştırıldığında zahmetlidir, ancak tembellik varsayılan olarak tehlikeli veya kötü gibi görünmektedir. Tehlikeli kodda sadece "tehlikeli".
sara,

1
@DeadMG Kodunuzun sonlandırılıp sonlandırılmayacağına aldırmıyorsanız ... head [1 ..]Size hevesle değerlendirilmiş bir saf dilde ne verir, çünkü Haskell'de verdiği gibi 1?
noktalı virgül

1
Birçok dil için tembel değerlendirme uygulamak en azından karmaşıklığı getirecektir. Bazen bu 'karmaşıklığa ihtiyaç duyulur ve tembel bir değerlendirmeye sahip olmak genel verimliliği arttırır - özellikle değerlendirilene yalnızca şartlı olarak ihtiyaç duyulduğunda. Ancak, kötü yapıldığında, kod yazarken yapılan yanlış varsayımlar nedeniyle performans sorunlarını açıklamak için ince hatalar olabilir veya zor olabilir. Bir takas var.
Berin Loritsch

17

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ç)


Evet, değişken durum + tembel değerlendirme = ölüm. SICP finalimde kaybettiğim tek puanın set!tembel bir Scheme tercümanında kullanılmasıyla ilgili olduğunu düşünüyorum . > :(
Tikhon Jelvis

3
"tembel kod ve durum kötü bir şekilde karışabilir": Gerçekten durumu nasıl uyguladığınıza bağlı. Paylaşılabilir değişken değişkenleri kullanarak uygularsanız ve durumunuzun tutarlı olması için değerlendirme sırasına bağlıysanız, haklısınız demektir.
Giorgio

14

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.


Gerçekten zeki bir derleyicinin ek yükü önemli ölçüde hafifletmesi mümkün olabilir mi . veya daha fazla optimizasyon için tembellikten bile faydalanmak?
Tikhon Jelvis

3

İş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.


1
“Bir değerin her kullanımında ek yükü defter tutma”: Defter tutma ek yükünün Java gibi bir dilde boş referansları kontrol etmekten daha büyük olduğunu sanmıyorum. Her iki durumda da, bir bit bilgiyi kontrol etmeniz (null değerine göre / null değerine göre değerlendirilmiş / null değerine bakılmaksızın) ve değeri her kullandığınızda yapmanız gerekir. Yani, evet, bir ek yükü var, ancak asgari düzeyde.
Giorgio

1
“Yazdığınız fonksiyonların kaç tanesi tüm argümanlarının değerlendirilmesini gerektirmiyor?”: Bu sadece bir örnek uygulama. Özyinelemeli, sonsuz veri yapıları hakkında ne? Onları istekli değerlendirme ile uygulayabilir misiniz? Yineleyicileri kullanabilirsiniz, ancak çözüm her zaman özlü değildir. Tabii ki muhtemelen hiç kullanma şansınız olmadı.
Giorgio

2
“Sonuç olarak, tembel değerlendirme ortalama olarak ortalama ödeme yapmıyor, istekli değerlendirme modern kod için daha uygun”.
Giorgio

1
@Giorgio Tepegöz size pek görünmeyebilir, ancak şartlı durumlar modern CPU'ların emdikleri şeylerden biridir: Yanlış öngörülen bir şube genellikle ondan fazla CPU döngüsünün çalışmasını ortadan kaldırarak tam bir boru hattını temizlemeye zorlar. İç döngüde gereksiz koşullar istemiyorsunuz. İşlev argümanı başına fazladan on döngü ödemek, java'daki şeyi kodlamak kadar performans duyarlı kod için neredeyse kabul edilemez. Tembel değerlendirmenin, istekli değerlendirmeyle kolayca yapamayacağınız bazı püf noktaları kaldırmanıza izin vermesi konusunda haklısınız. Ancak, kodun büyük çoğunluğunun bu numaralara ihtiyacı yoktur.
cmaster

2
Bu tembel değerlendirme dilleri ile deneyimsizliğin bir cevabı gibi görünüyor. Örneğin, sınırsız veri yapıları hakkında ne düşünüyorsunuz?
Andres F.

3

@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.


1
Tecrübesizliği tartışıyor gibisin. "Neden İşlevsel Programlama Önemlidir" yazısını Wadler tarafından okumanızı öneririm. Tembel değerlendirmenin nedenini açıklayan büyük bir bölüm ayırmaktadır (ipucu: performans, erken optimizasyon veya "nadiren erişilen verileri yükleme" ve modülerlikle ilgili her şeyi yapmakla çok az ilgisi vardır).
Andres F.

@AndresF Bahsettiğiniz kağıdı okudum. Bu gibi durumlarda tembel değerlendirme kullanımına katılıyorum. Erken değerlendirme uygun olmayabilir, ancak seçilen hamle için alt ağacı geri getirmenin, ek hamleler kolayca eklenebilirse, önemli bir faydası olabileceğini savunuyorum. Ancak, bu işlevselliği oluşturmak erken optimizasyon olabilir. İşlevsel programlama dışında, tembel değerlendirme ve tembel değerlendirme kullanmama konusunda önemli sorunlar var. İşlevsel programlamadaki tembel değerlendirmeden kaynaklanan önemli performans maliyetleriyle ilgili raporlar vardır.
BillThor

2
Gibi? İstekli değerlendirme kullanıldığında da önemli performans maliyetleri raporları vardır (gereksiz değerlendirme ve programın sona ermemesi gibi maliyetler). Neredeyse diğer (yanlış) kullanılan özelliklerin bir maliyeti vardır, bunu düşünün. Modülerliğin kendisi bir maliyetle gelebilir; Sorun buna değip değmeyeceği.
Andres F.

3

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.


“Yani, mesele şu ki, eldeki görev için en iyisini kullanmalısınız.” +1
Giorgio
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.