A -> () fonksiyonunun Haskell'de değerlendirilmesinde hangi kurallar vardır?


12

Tıpkı başlığın dediği gibi: Haskell fonksiyon geri dönen birimin değerlendirilmesi için ne gibi garantiler var? Böyle bir durumda herhangi bir değerlendirme yapmaya gerek olmadığını düşünebiliriz, ()açık bir kesinlik talebi olmadığı sürece derleyici bu tür tüm çağrıları hemen bir değerle değiştirebilir , bu durumda kodun gerekip gerekmediğine karar vermesi gerekebilir dönüş ()veya alt.
GHCi'de bunu denedim ve tam tersi gibi görünüyor, yani böyle bir fonksiyon değerlendirilmiş gibi görünüyor. Çok ilkel bir örnek

f :: a -> ()
f _ = undefined

Değerlendirme f 1, varlığı nedeniyle bir hata atar undefined, bu nedenle bazı değerlendirmeler kesinlikle gerçekleşir. Bununla birlikte, değerlendirmenin ne kadar derin olduğu açık değildir; bazen geri dönen işlevlere yapılan tüm çağrıları değerlendirmek gerektiği kadar derine inmiş gibi görünür (). Misal:

g :: [a] -> ()
g [] = ()
g (_:xs) = g xs

Bu kod, sunulduğu takdirde süresiz olarak döngüye girer g (let x = 1:x in x). Ama sonra

f :: a -> ()
f _ = undefined
h :: a -> ()
h _ = ()

h (f 1)dönüşleri göstermek için kullanılabilir (), bu durumda bu durumda birim değerli tüm alt ifadeler değerlendirilmez. Buradaki genel kural nedir?

ETA: tabii ki tembellik biliyorum. Derleyici yazarların bu özel durumu genellikle mümkün olandan daha tembel hale getirmesini neyin önlediğini soruyorum.

ETA2: örneklerin özeti: GHC, ()tam olarak başka herhangi bir tür gibi muamele ediyor gibi görünmektedir , yani, tipte yaşayan normal değerin bir işlevden döndürülmesi gerektiği hakkında bir soru varmış gibi. Böyle bir değerin sadece bir tane olması, (ab) optimizasyon algoritmaları tarafından kullanılmıyor gibi görünmektedir.

ETA3: Haskell dediğimde, GHC'de Haskell değil, Rapor tarafından tanımlanan Haskell'i kastediyorum. Tahmin ettiğim kadar paylaşılmayan bir varsayım gibi görünüyor (ki bu 'okurların% 100'ü' idi), ya da muhtemelen daha net bir soru formüle edebilirdim. Buna rağmen, sorunun başlığını değiştirdiğim için pişmanım, çünkü aslında böyle bir işlev için hangi garantilerin var olduğunu sordu .

ETA4: Görünüşe göre bu soru yoluna girdi ve ben de cevapsız olduğunu düşünüyorum. (Bir 'yakın soru' işlevi arıyordum ama sadece 'kendi sorunuzu cevaplayın' buldum ve cevaplanamadığı için bu rotaya inmedim.) Kimse Rapordan her iki şekilde de karar verecek bir şey getirmedi Bu da güçlü ama kesin olmayan bir 'dil için garanti yok' cevabı olarak yorumlamaya meyilliyim. Tek bildiğimiz, mevcut GHC uygulamasının böyle bir fonksiyonun değerlendirmesini atlamayacağıdır.

Haskell'e bir OCaml uygulaması taşırken asıl sorunla karşılaştım. Orijinal uygulama, birçok türde karşılıklı olarak özyinelemeli bir yapıya sahipti ve kod assert_structureN_is_correct, 1..6 veya 7'de N için çağrılan bir dizi işlev bildirdi ; bunların her biri, yapı gerçekten doğruysa birimi döndürdü ve değilse bir istisna attı . Ayrıca, bu işlevler doğruluk koşullarını çürüttükçe birbirlerini çağırdılar. Haskell'de bu, Either Stringmonad kullanılarak daha iyi ele alındı , bu yüzden onu bu şekilde kopyaladım, ancak teorik bir sorun olarak kaldı. Tüm girişler ve cevaplar için teşekkürler.


1
Bu işteki tembelliktir. Bir işlevin sonucu istenmedikçe (örneğin bir kurucuya karşı desen eşleşmesi ile), işlevin gövdesi değerlendirilmez. Farkı gözlemlemek için, karşılaştırma deneyin h1::()->() ; h1 () = ()ve h2::()->() ; h2 _ = (). Her iki çalıştırın h1 (f 1)ve h2 (f 1)ve bu sadece ilki taleplerini bkz (f 1).
Chi

1
"Tembellik, herhangi bir değerlendirme yapılmadan () ile değiştirildiğini söylüyor gibi görünüyor." Bu ne anlama geliyor? her durumda f 1"değiştirilir" undefined.
oisdk

3
Bir fonksiyon ... -> ()1) sonlanabilir ve geri dönebilir (), 2) bir istisna / çalışma zamanı hatası ile sonlanabilir ve hiçbir şey döndüremez veya 3) ayrışır (sonsuz özyineleme). GHC yalnızca 1) olabileceğini varsayarak kodu optimize etmez: f 1talep edilirse , değerlendirmesini ve geri dönüşünü atlamaz (). Haskell semantiği bunu değerlendirmek ve 1,2,3 arasında neler olduğunu görmek.
Chi

2
()Bu soruda (tip veya değer) gerçekten özel bir şey yok . Aynı gözlemler () :: (), örneğin 0 :: Inther yerle değiştirirseniz gerçekleşir . Bunların hepsi tembel değerlendirmenin sıkıcı eski sonuçlarıdır.
Daniel Wagner

2
hayır, "kaçınmak" vb. Haskell semantiği değildir. ve iki olası ()tip değeri vardır ()ve undefined.
Ness Ness

Yanıtlar:


10

Türün ()yalnızca bir olası değere sahip olduğu varsayımından geliyorsunuz ()ve bu nedenle , tür değerini döndüren herhangi bir işlev çağrısının ()otomatik olarak değeri ürettiği varsayılmasını bekliyorsunuz ().

Haskell böyle çalışmaz. Her türün Haskell'de bir değeri daha vardır, yani hiçbir değer, hata veya "alt" olarak kodlanır undefined. Böylece aslında bir değerlendirme yapılmaktadır:

main = print (f 1)

Çekirdek dilin karşılığıdır

main = _Case (f 1) _Of x -> print x   -- pseudocode illustration

hatta (*)

main = _Case (f 1) _Of x -> putStr "()"

ve Core en _Caseedilmektedir zorlayarak :

" %case[İfadenin] değerlendirilmesi, test edilen ifadenin değerlendirilmesini zorlar (" araştırmacı "). Araştırmacının değeri, %ofanahtar kelimeyi izleyen değişkene bağlıdır ...".

Değer zayıf kafa normal formuna zorlanır. Bu dil tanımının bir parçasıdır.

Haskell değil bir bildirim programlama dili.


(*) print x = putStr (show x) ve show () = "()"böylece showçağrı tamamen derlenebilir.

Değer gerçekten önceden bilinir ()ve hatta değeri show ()önceden bilinir "()". Yine de kabul edilen Haskell semantiği (f 1), önceden dizgide bilinen değeri yazdırmaya başlamadan önce değerinin zayıf kafa normal formuna zorlanmasını talep ediyor "()".


edit: düşünün concat (repeat []). Olmalı mı []yoksa sonsuz bir döngü mü olmalı?

"Açıklayıcı bir dil" in buna cevabı büyük olasılıkla []. Haskell'in cevabı, sonsuz döngü .

Tembellik ise "yoksul adamın bildirim programlama", ama yine de değil gerçek bir şey .

edit2 : print $ h (f 1) == _Case (h (f 1)) _Of () -> print ()ve sadece hzorla, değil f; ve üretmek için onun cevabını hkendi tanımına göre, bir şey zorlamak zorunda değildir h _ = ().

ayrılık sözleri: Tembellik, varoluş nedeni olabilir ama tanımı değildir. Tembellik budur. Başlangıçta gelen taleplere göre WHNF'ye zorlanan tüm değerler olarak tanımlanır main. Belirli koşullara göre belirli bir durumda dipten kaçınmaya yardımcı olursa, o zaman yapar. Eğer değilse, değil. Hepsi bu.

Bunu hissetmek için en sevdiğiniz dilde kendiniz uygulamanıza yardımcı olur. Ancak, tüm ara değerlerini oluştukça dikkatli bir şekilde adlandırarak herhangi bir ifadenin değerlendirmesini de izleyebiliriz .


Rapora gidiyoruz ,

f :: a -> ()
f = \_ -> (undefined :: ())

sonra

print (f 1)
 = print ((\ _ ->  undefined :: ()) 1)
 = print          (undefined :: ())
 = putStrLn (show (undefined :: ()))

Ve birlikte

instance Show () where
    show :: () -> String
    show x = case x of () -> "()"

Devam eder

 = putStrLn (case (undefined :: ()) of () -> "()")

Şimdi bölüm 3.17.3 Raporun Desen Eşleşmesinin Biçimsel Semantiği şöyle diyor:

caseİfadelerin anlambilimi Şekil 3.1-3.3'te verilmiştir. Herhangi bir uygulama, bu kimliklerin [...] sahip olacağı şekilde davranmalıdır.

ve örnek (r)olarak , Şekil 3.2 durumları

(r)     case  of { K x1  xn -> e; _ -> e } =  
        where K is a data constructor of arity n 

() 0 değerinin veri yapıcısı olduğundan, aynı

(r)     case  of { () -> e; _ -> e } =  

ve değerlendirmenin genel sonucu böyledir .


2
Açıklamanızı beğendim. Açık ve basit.
19:10 arrowd

@DanielWagner caseAslında Core dan aklıma vardı ve boşluk deliğini görmezden geliyordu. :) Çekirdekten bahsetmek için düzenledim.
Ness Ness

1
Olmak zorlayarak olmaz showtarafından çağrılan print? Gibi bir şeyshow x = case x of () -> "()"
user253751

1
Ben atıfta casedeğil Haskell kendisi, Core. Haskell, zorla caseAFAIK olan Çekirdeğe çevrildi . Bunu doğru caseHaskell kendisi tarafından zorla değil. Şema veya ML'de bir şey yazabilirim (eğer ML yazabilirsem) veya sözde kod.
Ness Ness

1
Tüm bunlara verilecek yetkili cevap muhtemelen Raporun bir yerinde. Tek bildiğim burada "optimizasyon" yok ve "normal değer" bu bağlamda anlamlı bir terim değil. Zorlanan ne varsa, zorla. printbaskı için gereken kadar zorlar. türe bakmaz, türler kaybolur, silinir, program çalıştığında, derleme zamanında türüne göre doğru yazdırma alt programı zaten seçilir ve derlenir; bu alt program hala giriş değerini çalışma zamanında WHNF'ye zorlar ve eğer tanımlanmamışsa bir hataya neden olur.
Ness Ness
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.