Haskell'in "hiçbir şey yapmama" işlevi neden tonlarca bellek tüketiyor?


112

Haskell, girdiyi değiştirmeden döndüren bir kimlik işlevine sahiptir. Tanım basit:

id :: a -> a
id x = x

Öyleyse, eğlence için bu çıktı 8:

f = id id id id id id id id id id id id id id id id id id id id id id id id id id id
main = print $ f 8

Birkaç saniye sonra (ve Görev Yöneticisine göre yaklaşık 2 gb bellek), ile derleme başarısız olur ghc: out of memory. Tercüman da benzer şekilde diyor ghci: out of memory.

Yana idoldukça basit bir fonksiyondur, bunun çalışma zamanında veya derleme zamanında bir bellek yük olmak istemem. Tüm hafıza ne için kullanılıyor?


11
Bunları bestelemek istiyorsunuz id. VIM olarak, tanımı üzerindeki imleç fBunu yapmak: :s/id id/id . id ./g.
Tobias Brandt

Yanıtlar:


135

Biz türünü biliyoruz id,

id :: a -> a

Ve bunun için uzmanlaştığımızda id id, sol kopyasının idtürü vardır:

id :: (a -> a) -> (a -> a)

Ve sonra soldaki yine bu uzman zaman idiçinde id id idelde edersiniz:

id :: ((a -> a) -> (a -> a)) -> ((a -> a) -> (a -> a))

Yani her ideklediğinizi görüyorsunuz , en soldaki tür imzası idiki kat daha büyük.

Türlerin derleme sırasında silindiğini unutmayın, bu nedenle bu yalnızca GHC'de bellek kaplar. Programınızda hafızayı kaplamaz.


Okasaki'nin Haskell'e gömülü bir RPN hesap makinesi yazdığında benzer bir sorunla karşılaştığını hatırlıyorum.
dfeuer

3
Belki de soru, GHC'nin bu tür şeyleri daha zarif bir şekilde halletmenin bir yolunu bulup bulmayacağıdır. Özellikle, tam olarak yazıldığında tür çok büyüktür, ancak muazzam miktarda tekrarlama vardır - bu tür şeyleri sıkıştırmak için paylaşım kullanılabilir mi? Bunları işlemenin etkili bir yolu var mı?
dfeuer

5
@dfeuer ghci'deki türü sormayı deneyin. Yanıtın hızına göre uygun paylaşımı yapması gerektiğini göreceksiniz. Bu paylaşımın - bariz nedenlerden dolayı - başka bir ara temsile (örneğin çekirdek) çevirdiğinizde kaybolduğundan şüpheleniyorum.
Daniel Wagner

4
Bu id, defalarca tekrarlanırsa n, türünün uzayının orantılı olduğu anlamına gelir 2^n. Ryan'ın kodunda çıkarılan 2^27tür, türü temsil etmek için gerekli olan diğer yapıya ek olarak tür değişkenine başvurulara ihtiyaç duyacaktır , ki bu muhtemelen çoğu türün olmasını beklediğinizden çok daha büyüktür.
David

58
Tip çıkarımını safça yapmak iki kat üsteldir, tür ifadelerinde akıllıca paylaşım kullanarak bunu sadece üstel hale getirebilirsiniz. Ancak ne yaparsanız yapın, yazım denetleyicisini patlatacak oldukça basit ifadeler olacaktır. Neyse ki bunlar pratik programlamada görülmez.
augustss
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.