Haskells Zayıf Kafa Normal Form


9

Bazı rahatsız edici şeyler üzerinde tökezledim. Haskell'in zayıf kafa normal formu (WHNF) ile çalıştığını biliyorum ve bunun ne olduğunu biliyorum. Aşağıdaki kodu ghci'ye yazarak (şu komutu kullanıyorum: ifadeyi WHNF'ye bilgime indirgeyen sprint):

let intlist = [[1,2],[2,3]]
:sprint intlist

veren intlist = _bu markaları tamamen bana seziyorum.

let stringlist = ["hi","there"]
:sprint stringlist 

veren stringlist = [_,_] bu beni zaten karıştırır. Ama sonra:

let charlist = [['h','i'], ['t','h','e','r','e']]
:sprint charlist

şaşırtıcı bir şekilde verir charlist = ["hi","there"]

Bildiğim kadarıyla Haskell anlaşıldığı gibi dizeleri türlerini kontrol ederek uyumlu görünmektedir karakter listeleri, daha başka bir şey değildir "hi" :: [Char]ve ['h','i'] :: [Char].

Kafam karıştı, çünkü benim anlayışımda yukarıdaki üç örneğin hemen hemen hepsi aynı (bir liste listesi) ve bu nedenle aynı WHNF'ye, yani _'e indirmeliler. Neyi kaçırıyorum?

Teşekkürler


Bu ilgili gibi görünüyor
Bergi

@Bergi bu sorularla kesinlikle ilgili, ama ikisi de nedenini ele almıyor gibi görünüyor "bla"ve ['b','l','a']farklı çıkacaktı.
leftaroundabout

@ leftaroundabout Çünkü "bla"aşırı yüklenebilir, ancak ['b','l','a']a String/ [Char]?
Bergi

1
@Bergi Ben de bunu düşündüm, ama gerçekten mantıklı çünkü değil ['b', 'l', 'a']olabilir ayrıca aşırı yüklenmiş aynı şekilde ve "bla"yalnızca aşırı -XOverloadedStringsaçıktır.
leftaroundabout

2
Ayrıştırıcıyla ilgili, muhtemelen GHCi'ye özgü görünüyor? (GHC-derlenmiş kodda WHNF için nasıl test yaptığınızı bilmiyorum.) Tırnaklar kendilerini tetikleyici gibi görünüyor.
chepner

Yanıtlar:


5

Not :sprintyok değil WHNF için bir ifade azaltır. Eğer öyleyse, aşağıdakiler 4yerine aşağıdakileri verecektir _:

Prelude> let four = 2 + 2 :: Int
Prelude> :sprint four
four = _

Aksine, :sprintbir bağlamanın adını alır, bağlamanın değerinin iç temsilini geçer ve _değerlendirilmemiş gövdeler için yer tutucu olarak (yani, askıya alınmış tembel işlev ) kullanılırken zaten "değerlendirilen parçaları" (yani, yapıcı olan parçaları) gösterir. ) çağırır. Değer tamamen değerlendirilmemişse, WHNF için bile hiçbir değerlendirme yapılmayacaktır. (Ve değer tamamen değerlendirilirse, bunu sadece WHNF değil, elde edersiniz.)

Deneylerinizde gözlemlediğiniz şey, polimorfik ve monomorfik sayısal tiplerin bir kombinasyonu, karakter dizileri için farklı dahili gösterimler ve açık karakter listeleri vb. Dolayısıyla, bu uygulama ayrıntılarını WHNF ile bir ilgisi olarak yorumlamak sizi umutsuzca şaşırtacak. Genel olarak, :sprintWHNF ve Haskell değerlendirmesinin anlambilimi hakkında bilgi edinmenin bir yolu olarak değil, yalnızca bir hata ayıklama aracı olarak kullanılmalıdır .

Gerçekten ne :sprintyaptığını anlamak istiyorsanız, ifadelerin gerçekte nasıl ele alındığını görmek için GHCi'de birkaç bayrağı açabilirsiniz ve sonunda bayt koduna derlenir:

> :set -ddump-simpl -dsuppress-all -dsuppress-uniques

Bundan sonra biz senin nedenini görebilirsiniz intlistverir _:

> let intlist = [[1,2],[2,3]]
==================== Simplified expression ====================
returnIO
  (: ((\ @ a $dNum ->
         : (: (fromInteger $dNum 1) (: (fromInteger $dNum 2) []))
           (: (: (fromInteger $dNum 2) (: (fromInteger $dNum 3) [])) []))
      `cast` <Co:10>)
     [])

returnIODış :çağrıyı ve dış çağrıyı görmezden gelebilir ve ile başlayan bölüme konsantre olabilirsiniz.((\ @ a $dNum -> ...

İşte $dNumiçin sözlük olan Numkısıtlaması. Oluşturulan kod henüz gerçek türü çözülmediği olduğu bu araçlar atürü Num a => [[a]]tüm ifade hala için (sözlük), uygun bir bir alarak bir işlev olarak temsil edilir, böylece Numtürü. Başka bir deyişle, değerlendirilmemiş bir thunk ve şunu elde ediyoruz:

> :sprint intlist
_

Öte yandan, türü olarak belirtin Intve kod tamamen farklıdır:

> let intlist = [[1::Int,2],[2,3]]
==================== Simplified expression ====================
returnIO
  (: ((: (: (I# 1#) (: (I# 2#) []))
         (: (: (I# 2#) (: (I# 3#) [])) []))
      `cast` <Co:6>)
     [])

ve böylece :sprintçıktı:

> :sprint intlist
intlist = [[1,2],[2,3]]

Benzer şekilde, değişmez dizeler ve açık karakter listeleri tamamen farklı temsillere sahiptir:

> let stringlist = ["hi", "there"]
==================== Simplified expression ====================
returnIO
  (: ((: (unpackCString# "hi"#) (: (unpackCString# "there"#) []))
      `cast` <Co:6>)
     [])

> let charlist = [['h','i'], ['t','h','e','r','e']]
==================== Simplified expression ====================
returnIO
  (: ((: (: (C# 'h'#) (: (C# 'i'#) []))
         (: (: (C# 't'#)
               (: (C# 'h'#) (: (C# 'e'#) (: (C# 'r'#) (: (C# 'e'#) [])))))
            []))
      `cast` <Co:6>)
     [])

ve :sprintçıktıdaki farklılıklar, GHCi ifadesinin hangi bölümlerinin değerlendirilmemiş (açık :kurucular) ile değerlendirilmemiş ( unpackCString#thunks) karşısındaki yapaylıkları temsil eder .

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.