Haskell üretim kodunda seq hangi sıklıkla kullanılır?


23

Haskell'de küçük aletler yazma konusunda bazı deneyimlerim var ve özellikle interactstandart girişlerini işleyen ve standart çıkışa yönlendiren filtreler yazmak için kullanmayı çok sezgisel buluyorum .

Geçenlerde böyle bir filtreyi normalden 10 kat daha büyük bir dosyada kullanmaya çalıştım ve bir Stack space overflowhata aldım .

Biraz okuma yaptıktan sonra (örneğin burada ve burada ) Yığın alanından tasarruf etmek için iki kılavuz belirledim (deneyimli Haskellers, lütfen doğru olmayan bir şey yazarsam düzeltin):

  1. Özyinelemeli özyinelemeli olmayan özyinelemeli işlev çağrıları kullanmaktan kaçının (bu, özyönelti optimizasyonunu destekleyen tüm işlevsel diller için geçerlidir).
  2. seqAlt ifadelerin erken değerlendirmesini zorlamak için tanıtın , böylece ifadeler azaltılmadan çok fazla büyümez (Haskell'e veya en azından tembel değerlendirme kullanan dillere özgüdür).

Koduma beş veya altı seqçağrı yaptıktan sonra , aracım tekrar sorunsuz çalışıyor (ayrıca daha büyük verilerde). Ancak, orijinal kodun biraz daha okunaklı olduğunu gördüm.

Tecrübeli bir Haskell programcısı olmadığımdan seq, bu şekilde tanıtmanın yaygın bir uygulama olup olmadığını ve seqHaskell üretim kodunda ne sıklıkta göreceğini sormak istedim . Yoksa seqçok sık kullanmamaya ve çok az yığın alanı kullanmaya izin veren herhangi bir teknik var mı?


1
Tanımladığınız tür gibi optimizasyonlar neredeyse her zaman kodu biraz daha az zarif hale getirecek.
Robert Harvey,

@Robert Harvey: Yığın kullanımını düşük tutmak için alternatif teknikler var mı? Demek istediğim, işlevlerimi farklı bir şekilde yeniden yazmak zorunda olduğumu hayal ediyorum ama köklü tekniklerin olup olmadığı hakkında hiçbir fikrim yok. İlk girişimim, sorunumu tamamen çözmeme izin vermeyen, ancak özyinelemeli işlevleri kullanmaktı.
Giorgio

Yanıtlar:


17

Ne yazık ki seq, büyük veriler için verimli / iyi çalışan bir program elde etmek için birinin kullanılması gereken durumlar vardır . Bu yüzden birçok durumda, üretim kodunda onsuz yapamazsınız. Daha fazla bilgiyi Real World Haskell, Bölüm 25'te bulabilirsiniz . Profil oluşturma ve optimizasyon .

Bununla birlikte, seqdoğrudan kullanmaktan nasıl kaçınabileceği olasılıkları vardır . Bu, kodu daha temiz ve daha güçlü hale getirebilir. Bazı fikirler:

  1. Kullanım kanalı , boru veya iteratees yerine interact. Tembel IO'nun kaynakları yönetmede sorun yaşadığı bilinmektedir (sadece hafıza değil) ve yinelemeler de tam olarak bunun üstesinden gelmek için tasarlanmıştır. (Verilerinizin büyüklüğü ne olursa olsun, tembel IO’yu tamamen önlemenizi öneririm - bkz . Tembel I / O’da sorun .)
  2. seqDoğrudan kullanmak (veya kendi tasarımınızı kullanmak) yerine, foldl ' veya foldr' gibi birleştiricileri veya katı hesaplamalar için tasarlanmış kitaplıkların ( Data.Map.Strict veya Control.Monad.State.Strict gibi ) katı sürümlerini kullanın .
  3. BangPatterns uzantısını kullanın . seqSıkı desen eşleştirmesi ile değiştirilmesine izin verir . Bildirilmesi sıkı yapıcı alanlarını da bazı durumlarda yararlı olabilir.
  4. Değerlendirmeye zorlamak için Stratejiler kullanmak da mümkündür . Stratejiler kütüphanesi çoğunlukla paralel hesaplamalara yöneliktir, ancak WHNF ( rseq) veya full NF ( rdeepseq) değerine zorlama yöntemleri de vardır. Koleksiyonlarla çalışmak, stratejileri birleştirmek vb. İçin birçok faydalı yöntem vardır.

+1: Yararlı ipuçları ve bağlantılar için teşekkür ederiz. 3. Nokta oldukça ilginç görünüyor (ve şu anda kullanmam için en kolay çözüm). Öneri 1 ile ilgili olarak, tembel IO'dan kaçınmanın işleri iyileştirebileceğini görmüyorum: Tembel IO'nun (muhtemelen çok uzun) bir veri akışını işlemesi beklenen bir filtre için daha iyi olması gerektiğini anlamıyorum.
Giorgio

2
@ Giorgio, Lazy IO ile ilgili sorunlar hakkında Haskell Wiki'ye bir link ekledim. Tembel IO ile kaynakları yönetmek için çok zor zamanlar geçirebilirsiniz. Örneğin, girişi tam olarak okumazsanız (tembel değerlendirme nedeniyle olduğu gibi), dosya tanıtıcısı açık kalır . Ve eğer dosya tanıtıcısını el ile kapatıp kapatırsanız, çoğu zaman tembel değerlendirme okuması nedeniyle ertelenir ve tüm girişi okumadan önce tanıtıcıyı kapatırsınız. Ve tembel IO ile hafıza problemlerinden kaçınmak genellikle oldukça zordur.
Petr Pudlák

Son zamanlarda bu sorunu yaşadım ve programımın dosya tanımlayıcıları tükeniyordu. Bu yüzden tembel IO'yu katı kullanarak katı IO ile değiştirdim ByteString.
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.