GHC, fonksiyonları hafızaya almaz.
Bununla birlikte, kodda verilen herhangi bir ifadeyi, çevreleyen lambda ifadesinin girildiği anda en fazla bir kez veya en üst düzeydeyse en fazla bir kez hesaplar. Lambda ifadelerinin nerede olduğunu belirlemek, örneğinizdeki gibi sözdizimsel şekeri kullandığınızda biraz zor olabilir, bu yüzden bunları eşdeğer desugared sözdizimine çevirelim:
m1' = (!!) (filter odd [1..]) -- NB: See below!
m2' = \n -> (!!) (filter odd [1..]) n
(Not: Haskell 98 raporu aslında bir sol operatör bölümünü (a %)
eşdeğer olarak \b -> (%) a b
tanımlıyor, ancak GHC bunu tasarlıyor (%) a
. Bunlar teknik olarak farklı çünkü ayırt edilebiliyorlar seq
. Sanırım bununla ilgili bir GHC Trac bileti göndermiş olabilirim.)
Bu göz önüne alındığında, söz konusu in görebilirsiniz m1'
ifade filter odd [1..]
sadece programın vadede başına bir kez bilgisayarlı olacak böylece iken, herhangi bir lambda-ifadesinde yer almayan m2'
, filter odd [1..]
lambda-ifadesi girildiğinde her zaman bilgisayarlı olacak yani her çağrıda m2'
. Bu gördüğünüz zamanlamadaki farkı açıklıyor.
Aslında, belirli optimizasyon seçeneklerine sahip bazı GHC sürümleri, yukarıdaki açıklamanın gösterdiğinden daha fazla değeri paylaşacaktır. Bu, bazı durumlarda sorunlu olabilir. Örneğin, işlevi düşünün
f = \x -> let y = [1..30000000] in foldl' (+) 0 (y ++ [x])
GHC y
, bunun bağlı olmadığını fark edebilir x
ve işlevi yeniden yazar.
f = let y = [1..30000000] in \x -> foldl' (+) 0 (y ++ [x])
Bu durumda, yeni sürüm, y
depolandığı yerden yaklaşık 1 GB okumak zorunda kalacağı için , orijinal sürüm sabit alanda çalışacak ve işlemcinin önbelleğine sığacağı için çok daha az verimlidir . Aslında, GHC 6.12.1 altında, işlev f
, optimizasyon yapılmadan derlendiğinde derlendiğinden neredeyse iki kat daha hızlıdır -O2
.
seq
m1 10000000). Optimizasyon bayrağı belirtilmediğinde bir fark vardır. Ve bu arada, "f" nin her iki varyantı da optimizasyondan bağımsız olarak 5356 baytlık maksimum ikametgahına sahiptir (-O2 kullanıldığında daha az toplam tahsis ile).