İşte Haskell nasıl yapıyor: (Haskell Nesneye Yönelik bir dil olmadığından Lippert'in ifadelerine tam olarak uymaz).
UYARI: Önümüzdeki ciddi bir Haskell fanatiğinden uzun soluklu cevap.
TL; DR
Bu örnek Haskell'in C # 'dan ne kadar farklı olduğunu göstermektedir. Yapı inşaatının lojistiğini bir kurucuya devretmek yerine, çevre kodunda ele alınmalıdır. Bir boş (veya NothingHaskell'de) değer değerinin boş olmayan bir değer beklediğimiz yerde kesmesine imkan yoktur, çünkü boş değerler yalnızca Maybedoğrudan, doğrudan normalden dönüştürülebilen ve normalden dönüştürülemeyen özel sargılı türlerde oluşabilir. null türleri N'ye sarılarak null yapılabilen bir değeri kullanmak için Maybe, önce kontrol eşlemesini boş olmayan bir değere sahip olduğumuzu bildiğimiz bir dallamaya yönlendirmeye zorlayan, kalıp eşleştirme kullanarak değeri çıkarmamız gerekir.
Bu nedenle:
Null edilemeyen bir referansın hiçbir zaman geçersiz olduğu gözlemlenen koşullar altında olmadığını her zaman bilebilir miyiz?
Evet. Intve Maybe Intiki tamamen ayrı tipler. Bulma Nothingbir ovada Intbir dize "balık" bulma karşılaştırılabilir olacaktır Int32.
NULL olmayan bir referans türü olan bir nesnenin yapıcısına ne demeli?
Sorun değil: Haskell'deki değer yapıcıları hiçbir şey yapamazlar, verilen değerleri alıp bir araya getirirler. Tüm başlatma mantığı, yapıcı çağrılmadan önce gerçekleşir.
Peki ya referansı doldurması gereken kod bir istisna attığı için böyle bir nesnenin sonlandırıcısında, nesnenin sonlandırıldığı yerde?
Haskell'de kesinleştiriciler yok, bu yüzden gerçekten buna değinemiyorum. Ancak ilk cevabım hala geçerli.
Tam Cevap :
Haskell'in boş değeri yoktur ve boş Maybealanları temsil etmek için veri türünü kullanır . Belki de bunun gibi tanımlanmış bir cebirsel veri türüdür :
data Maybe a = Just a | Nothing
Haskell'ı tanımayanlar için bunu "A Maybeya a Nothingya da a Just a" olarak okuyunuz . özellikle:
Maybeolduğu bir tipte : (bir genel sınıf olarak (yanlış) düşünülebilir atipi değişkendir). C # analojisidir class Maybe<a>{}.
Justbir değer yapıcısı : bir tür argümanı alan ave değeri Maybe aiçeren bir tür değeri döndüren bir işlevdir . Yani kod x = Just 17benzer int? x = 17;.
Nothingbaşka bir değer kurucu, ancak hiçbir argüman almaz ve Maybegeri dönen, "Hiçbirşey" den başka bir değere sahip değildir. x = Nothingbenzerdir int? x = null;(biz bizim kısıtlı varsayarak aHaskell olmak Intyazılı yapılabilir, hangi x = Nothing :: Maybe Int).
Şimdi, Maybetürün temelleri ortadan kalktığına göre Haskell, OP'nin sorusunda tartışılan sorunları nasıl önler?
Haskell, şu ana kadar tartışılan dillerin çoğundan gerçekten farklı, bu yüzden birkaç temel dil ilkesini açıklayarak başlayacağım.
Öncelikle, Haskell'de her şey değişmez . Her şey. Adlar, değerlerin saklanabileceği yerlere değil, değerlere atıfta bulunur (bu yalnızca büyük bir hata giderme kaynağıdır). Değişken bildirim ve atama değerlerini tanımlayarak oluşturulan Haskell değerlerinde iki ayrı operasyon vardır C #, aksine (örneğin x = 15, y = "quux", z = Nothing), asla değiştiremezsin ki. Bu nedenle, kod gibi:
ReferenceType x;
Haskell'de mümkün değil. Değerlerin başlatılması ile ilgili hiçbir sorun yoktur, nullçünkü her şeyin var olması için açıkça bir değere başlatılması gerekir.
İkincisi, Haskell nesne yönelimli bir dil değildir : tamamen işlevsel bir dildir, dolayısıyla kelimenin tam anlamıyla hiçbir nesne yoktur. Bunun yerine, argümanlarını alan ve birleştirilen bir yapı döndüren işlevler (değer yapıcıları) vardır.
Sonra, kesinlikle bir zorunlu stil kodu yoktur. Bununla, çoğu dilin böyle bir örüntü izlediğini kastediyorum:
do thing 1
add thing 2 to thing 3
do thing 4
if thing 5:
do thing 6
return thing 7
Program davranışı bir dizi talimat olarak ifade edilir. Nesne Yönelimli dillerde, sınıf ve işlev bildirimleri de program akışında büyük rol oynar, ancak esastır, bir programın yürütülmesinin "eti" yürütülmesi gereken bir dizi talimat biçimini alır.
Haskell'de bu mümkün değildir. Bunun yerine, program akışı tamamen zincirleme işlevleriyle belirlenir. Emir dokuvveti arayan gösterim bile isimsiz işlevleri >>=operatöre aktarmak için sadece sözdizimsel bir şeker . Tüm fonksiyonlar şu şekildedir:
<optional explicit type signature>
functionName arg1 arg2 ... argn = body-expression
body-expressionBir değeri değerlendiren herhangi bir şey nerede olabilir. Açıkçası daha fazla sözdizimi özellikleri mevcut ancak ana nokta, ifadelerin dizisinin tam olmamasıdır.
Son olarak, ve muhtemelen en önemlisi, Haskell'in tür sistemi inanılmaz derecede katıdır. Haskell'in tip sisteminin merkezi tasarım felsefesini özetlemek zorunda olsaydım derdim: "Derleme zamanında mümkün olduğunca çok şeyin yanlış gitmesini sağlayın, böylece çalışma zamanında olabildiğince az yanlış yapın." Hiçbir örtük dönüşüm (bir tanıtmak isteyen var Inta Double? Kullanın fromIntegralfonksiyonu). Çalışma zamanında meydana gelen geçersiz bir değere sahip olan tek şey kullanmaktır Prelude.undefined(görünüşe göre sadece orada olması ve kaldırılması imkansızdır ).
Bütün bunlar göz önünde bulundurularak, Amon'un "kırık" örneğine bakalım ve bu kodu Haskell'de tekrar ifade etmeye çalışalım. İlk olarak, veri bildirimi (adlandırılmış alanlar için kayıt sözdizimini kullanarak):
data NotSoBroken = NotSoBroken {foo :: Foo, bar :: Bar }
( foove bargerçekten asıl alanlar yerine anonim alanlara erişim işlevi görür, ancak bu ayrıntıyı yok sayabiliriz).
NotSoBrokenDeğeri yapıcı bir alma dışında herhangi bir işlem alma yeteneğinde olmayan Foove Bar(null değildir) ve bir alma NotSoBrokenbunların out. Zorunlu kod koymak veya hatta alanları manuel olarak atamak için yer yoktur. Tüm başlatma mantığı, başka bir yerde, büyük olasılıkla özel bir fabrika fonksiyonunda gerçekleşmelidir.
Örnekte, Brokenher zaman yapılaşma başarısız olur. NotSoBrokenDeğer yapıcısını benzer bir şekilde kırmanın bir yolu yoktur (kodu yazacak hiçbir yer yoktur), ancak benzer şekilde hatalı olan bir fabrika işlevi oluşturabiliriz.
makeNotSoBroken :: Foo -> Bar -> Maybe NotSoBroken
makeNotSoBroken foo bar = Nothing
(ilk satır bir tür imza bildirimidir: makeNotSoBrokena Foove Bara'yı argüman olarak alır ve a üretir Maybe NotSoBroken).
Geri dönüş tipi, Maybe NotSoBrokenbasitçe NotSoBrokendeğerlendirmek zorunda olduğumuz için değil Nothing, bunun için bir değer yapıcısı olduğu söylenmelidir Maybe. Farklı bir şey yazsaydık, türler sıraya girmezdi.
Kesinlikle anlamsız olmasının yanı sıra, bu işlev ne zaman kullanacağımızı göreceğimiz gibi asıl amacını bile yerine getirmiyor. Bir argüman olarak useNotSoBrokenbekleyen bir fonksiyon yaratalım NotSoBroken:
useNotSoBroken :: NotSoBroken -> Whatever
( bir argümanı useNotSoBrokenkabul eder NotSoBrokenve üretir Whatever).
Ve bu şekilde kullanın:
useNotSoBroken (makeNotSoBroken)
Çoğu dilde, bu tür davranışlar boş gösterici istisnalarına neden olabilir. Haskell'de türler eşleşmiyor: a makeNotSoBrokendöndürür Maybe NotSoBroken, ancak a useNotSoBrokenbekler NotSoBroken. Bu türler birbirlerinin yerine geçemez ve kod derlenemez.
Bunu aşmak caseiçin Maybedeğerin yapısına dayanarak dallara yapılan bir ifade kullanabiliriz ( desen eşleme adı verilen bir özelliği kullanarak ):
case makeNotSoBroken of
Nothing -> --handle situation here
(Just x) -> useNotSoBroken x
Açıkçası, bu pasajın aslında derlemek için bir bağlamın içine yerleştirilmesi gerekiyor, ancak Haskell'in nullaları nasıl idare ettiğinin temellerini gösteriyor. Yukarıdaki kodun adım adım açıklaması:
- Birincisi,
makeNotSoBrokenbir tür değer üretmesi garanti edilen değerlendirilir Maybe NotSoBroken.
caseİfadesi bu değerin yapısını inceler.
- Değer ise
Nothing, "burada durum ele" kodu değerlendirilir.
- Değer, bunun yerine bir
Justdeğerle eşleşirse, diğer dal yürütülür. Eşleşen maddenin eşzamanlı olarak değeri bir Justyapı olarak nasıl tanımladığını ve iç NotSoBrokenalanını bir isme nasıl bağladığını not edin (bu durumda, x). xdaha sonra normal NotSoBrokendeğer gibi kullanılabilir .
Bu nedenle, desen eşleştirme, tür güvenliğini sağlamak için güçlü bir olanak sağlar, çünkü nesnenin yapısı kontrolün dallanmasına ayrılmaz bir şekilde bağlıdır.
Umarım bu anlaşılabilir bir açıklama olmuştur. Eğer mantıklı değilse, Büyük İyilik İçin Size Bir Haskell Öğrenin! , şimdiye kadar okuduğum en iyi çevrimiçi dil öğreticilerinden biri. İnşallah aynı güzelliği yaptığım bu dilde göreceksiniz.