SORU
29 Temmuz 2011, Cuma


Zayıf Normal Form Başı Ne?Haskell:

NedirZayıf Head Normal Form(WHNF)? NedirHead Normal form(HNF)Normal Form(NF)?

Real World Haskell devletler:

Tanıdık seq işlevi kafa dediğimiz bir ifade olarak değerlendirilir normal form (kısaltılmış HNF). Dıştaki ulaştıktan sonra durur (“”) head. kurucu Bu normal form (BSA) ' dan farklı olduğunu bir ifade tamamen değerlendirilir.

Ayrıca Haskell programcılar zayıf head normal form bakın duyacaksınız (WHNF). Normal veriler için, zayıf head normal form kafa aynıdır normal form. Fark sadece fonksiyonlar için ortaya çıkar, ve çok derin burada bizi ilgilendiren.

Kaynakları ve tanımlar (Haskell Wiki 50* 51*) bir kaç okudum ama anlamadım. Birileri belki de bir örnek ver ya da meslekten olmayan bir tanım verebilir?

Benzer şekilde olacağını tahmin ediyorum:

WHNF = thunk : thunk

HNF = 0 : thunk 

NF = 0 : 1 : 2 : 3 : []

Nasıl seq ($!) WHNF ve HNF için ile ilgili?

Güncelleme

Hala kafam karışık. Bazı cevapları HNF görmezden söylediğini biliyorum. Çeşitli tanımları okuyarak WHNF ve HNF düzenli veri arasında fark yok gibi görünüyor. Ancak, bir işlevi söz konusu olduğunda bir fark var gibi görünüyor. Eğer bir fark varsa, hayır, neden seq foldl' için gerekli mi?

seq WHNF azaltır belirten Haskell Wiki gelen karışıklık bir diğer husus da, aşağıdaki örnek için hiçbir şey yapacağız. Sonra seq değerlendirme için güç kullanmak zorunda kaldıklarını söylüyor. Bu HNF zorluyor değil mi?

Ortak çaylak yığın kod taşan:

   myAverage = uncurry (/) . foldl' (\(acc, len) x -> (acc x, len 1)) (0,0)

Seq ve zayıf head normal form (whnf) anlayan insanlar olabilir yanlış burada neler olduğunu hemen anlıyor. (acc x, len 1) zaten. whnf, whnf için bir değeri azaltır yani seq, bu zor bir şey. Bu kod sadece orijinal foldl örneği gibi thunk kuracaksınız sadece bir demet içinde olacaklar. Bu çözüm sadece güç için. demet, örneğin bileşenleri

   myAverage = uncurry (/) . foldl' 
             (\(acc, len) x -> acc `seq` len `seq` (acc x, len 1)) (0,0)

-Haskell Wiki on Stackoverflow

CEVAP
31 Temmuz 2011, Pazar


Basitçe bir açıklama yapmaya çalışacağım. Diğerleri belirttiği gibi, kafa normal şeklini burada değerlendireceğim çok Haskell için geçerli değildir.

Normal form

Normal şeklinde bir ifade tam olarak değerlendirilir ve alt-ifade hiçbir başka (yani BM değerlendirip hayır thunk içerir) değerlendirilebilir.

Bu ifadeler, normal bir form var

42
(2, "hello")
\x -> (x   1)

Bu ifadeler normal formda değildir:

1   2                 -- we could evaluate this to 3
(\x -> x   1) 2       -- we could apply the function
"he"    "llo"         -- we could apply the (  )
(1   1, 2   2)        -- we could evaluate 1   1 and 2   2

Zayıf head normal form

Normal form dış veri kurucu veya lambda soyutlama değerlendirilmiş zayıf kafasında bir ifade (baş). Alt ifadelerolabilir ya da değerlendirilmiştir olmayabilir. Bu nedenle, her normal form ifadenin tersi genelde tutmaz olsa da zayıf head normal form.

İfadesi zayıf head normal form olup olmadığını belirlemek için, biz sadece ifade birikmesi bakmak zorunda. Eğer ya da lambda veri yapıcı ise, zayıf head normal form. Eğer işlev bir uygulama varsa, değil.

Bu ifadeler zayıf head normal form:

(1   1, 2   2)       -- the outermost part is the data constructor (,)
\x -> 2   2          -- the outermost part is a lambda abstraction
'h' : ("e"    "llo") -- the outermost part is the data constructor (:)

Belirtildiği gibi, tüm normal form ifadeler yukarıda listelenen zayıf head normal form.

Bu ifadeler zayıf head normal form: değildir

1   2                -- the outermost part here is an application of ( )
(\x -> x   1) 2      -- the outermost part is an application of (\x -> x   1)
"he"    "llo"        -- the outermost part is an application of (  )

Yığın uzaklıklarını aşıyor

Zayıf head normal form için bir ifade değerlendirmek diğer ifadeler ilk WHNF için değerlendirilmesi gerekebilir. Örneğin, 1 (2 3) WHNF değerlendirmek için, öncelikle 2 3 değerlendirmek zorunda. Eğer tek bir deyimi değerlendirmek, bu değerlendirmeler, iç içe geçmiş pek çok neden, sonuç, yığın taşması olur.

Bu herhangi bir veri kurucular üretmez büyük bir ifade oluştururken olur veya büyük bir kısmı değerlendirilmiş kadar Lambda. Bunlar genellikle foldl kullanımı bu tür neden olur:

foldl ( ) 0 [1, 2, 3, 4, 5, 6]
 = foldl ( ) (0   1) [2, 3, 4, 5, 6]
 = foldl ( ) ((0   1)   2) [3, 4, 5, 6]
 = foldl ( ) (((0   1)   2)   3) [4, 5, 6]
 = foldl ( ) ((((0   1)   2)   3)   4) [5, 6]
 = foldl ( ) (((((0   1)   2)   3)   4)   5) [6]
 = foldl ( ) ((((((0   1)   2)   3)   4)   5)   6) []
 = (((((0   1)   2)   3)   4)   5)   6
 = ((((1   2)   3)   4)   5)   6
 = (((3   3)   4)   5)   6
 = ((6   4)   5)   6
 = (10   5)   6
 = 15   6
 = 21

Zayıf kafa ifadeye normal form geçmeden oldukça derin gitmek ne kadar kötü bir haber.

Neden Haskell iç ifadeler vaktinden azaltmaz merak edebilir? Bu Haskell'ın tembellik yüzünden. Her ifadeyi gerekli olacak genel olarak kabul edilemez bu yana, ifadeler dışında, değerlendirilir.

(DZD bir ifadeyi her zaman olması gereken bazı durumları tespit edecek katılık analiz etti ve sonra onu vaktinden değerlendirebilir. Bu sadece bir iyileştirme olduğunu, ancak, ve taşmaları kurtarmak için kullanır) olmamalıdır.

Bu tür bir ifade, diğer taraftan, tamamen güvenli

data List a = Cons a (List a) | Nil
foldr Cons Nil [1, 2, 3, 4, 5, 6]
 = Cons 1 (foldr Cons Nil [2, 3, 4, 5, 6])  -- Cons is a constructor, stop. 

Tüm taşıyıcının değerlendirilecek olacak biliyorum, bu büyük ifadeleri bina önlemek için, iç kısımlarında vaktinden değerlendirilecek zorlamak istiyoruz.

seq

seq ifadeler değerlendirilecek zorlamak için kullanılan özel bir işlevdir. Anlambilimi y zayıf head normal form için değerlendirildiği zaman, x da zayıf head normal form olarak değerlendirilir seq x y anlamına gelir.

Diğer yerler foldl', foldl sıkı varyant tanımında kullanılan arasında yer alıyor.

foldl' f a []     = a
foldl' f a (x:xs) = let a' = f a x in a' `seq` foldl' f a' xs

foldl' her tekrarında akümülatör WHNF zorlar. Bu nedenle büyük bir ifade bina önler ve bu nedenle yığın taşan önler.

foldl' ( ) 0 [1, 2, 3, 4, 5, 6]
 = foldl' ( ) 1 [2, 3, 4, 5, 6]
 = foldl' ( ) 3 [3, 4, 5, 6]
 = foldl' ( ) 6 [4, 5, 6]
 = foldl' ( ) 10 [5, 6]
 = foldl' ( ) 15 [6]
 = foldl' ( ) 21 []
 = 21                           -- 21 is a data constructor, stop.

Ama HaskellWiki örnek bahseder gibi, bu akümülatör sadece WHNF için değerlendirilir olarak her durumda size tasarruf etmez. Bu örnekte, akümülatör bir demet, sadece demet Kurucu, ve değil acc len değerlendirme zorlar.

f (acc, len) x = (acc   x, len   1)

foldl' f (0, 0) [1, 2, 3]
 = foldl' f (0   1, 0   1) [2, 3]
 = foldl' f ((0   1)   2, (0   1)   1) [3]
 = foldl' f (((0   1)   2)   3, ((0   1)   1)   1) []
 = (((0   1)   2)   3, ((0   1)   1)   1)  -- tuple constructor, stop.

Bunu önlemek için, başlığın yapıcı değerlendirme acc len değerlendirme güçler bunu yapmak zorundayız. seq kullanarak bunu yaparız.

f' (acc, len) x = let acc' = acc   x
                      len' = len   1
                  in  acc' `seq` len' `seq` (acc', len')

foldl' f' (0, 0) [1, 2, 3]
 = foldl' f' (1, 1) [2, 3]
 = foldl' f' (3, 2) [3]
 = foldl' f' (6, 3) []
 = (6, 3)                    -- tuple constructor, stop.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Sergio Fernandez

    Sergio Ferna

    1 EKİM 2009
  • Subscribe!!

    Subscribe!!

    3 EKİM 2009
  • William Hyde

    William Hyde

    23 HAZİRAN 2008