Yanıtlar:
Temelde aynı şekilde çalışan ancak yerine rastgele bir değer döndürmenize izin veren Maybe
kuzenini kullanmak , istisnalardan biraz farklı bir amaca hizmet eder. Java açısından, bir çalışma zamanı istisnası yerine işaretli bir istisna olması gibi. Bir şeyler temsil beklenen sen daha çok beklemiyorduk bir hata daha uğraşmak zorunda.Either
Nothing
Öyleyse, gibi bir işlev indexOf
bir Maybe
değer döndürür çünkü öğenin listede olmaması ihtimalini beklersiniz. Bu, null
sizi null
durumla başa çıkmaya zorlayan güvenli bir yöntem dışında, bir işlevden geri dönmeye benzer . Either
hata durumuyla ilişkili bilgileri geri verebilmeniz dışında aynı şekilde çalışır, bu yüzden aslında bir istisna dışındadır Maybe
.
Peki Maybe
/ Either
yaklaşımın avantajları nelerdir? Birincisi, dilin birinci sınıf vatandaşı. Bir işlev kullanarak Either
bir istisna atan bir işlevi karşılaştıralım . İstisna durumu için tek gerçek başvurunuz bir try...catch
ifadedir. İçin Either
fonksiyonu, sen akış kontrolü daha anlaşılır hale getirmek için mevcut combinators kullanabilirsiniz. Burada bir çift örnek var:
Öncelikle, üst üste hata yapabilecek birkaç işlevi denemek istediğinizi varsayalım. Herhangi bir hatasızlık alamazsanız, özel bir hata mesajı döndürmek istersiniz. Bu aslında çok kullanışlı bir kalıp ama kullanımı korkunç bir acı olurdu try...catch
. Neyse ki, Either
normal bir değer olduğu için kodu daha net hale getirmek için mevcut işlevleri kullanabilirsiniz:
firstThing <|> secondThing <|> throwError (SomeError "error message")
Başka bir örnek isteğe bağlı bir işleve sahip olmaktır. Diyelim ki, bir sorguyu optimize etmeye çalışan biri dahil olmak üzere, çalıştırmanız gereken çeşitli işlevleriniz var. Bu başarısız olursa, her şeyin başka şekilde çalıştırılmasını istersiniz. Gibi bir şey kod yazabilirsiniz:
do a <- getA
b <- getB
optional (optimize query)
execute query a b
Bu davaların ikisi de kullanmaktan daha net ve kısa try..catch
ve daha da önemlisi daha anlamlıdır. Gibi bir işlev kullanmak <|>
veya optional
niyetlerinizi, istisnaları her zaman işlemek için kullanmaktan daha açık bir şekilde yapar try...catch
.
Ayrıca , kodunuzu bunun gibi satırlarla doldurmanız gerekmediğini unutmayın if a == Nothing then Nothing else ...
! Tedavi Maybe
ve Either
bir monad olarak tüm mesele, bundan kaçınmaktır. Yayılma anlamını bind fonksiyonuna kodlayabilirsiniz, böylece null / error kontrollerini ücretsiz alabilirsiniz. Eğer başka bir şey dönmek isterseniz açık bir şekilde kontrol etmek zorunda tek zaman Nothing
verilen bir Nothing
bu kod daha güzel hale getirmek için standart kütüphane fonksiyonları bir grup vardır: ve hatta o zaman kolaydır.
Son olarak, bir başka avantaj da Maybe
/ Either
tipinin daha basit olmasıdır. Dili ek anahtar kelimeler veya kontrol yapılarıyla genişletmeye gerek yoktur - her şey sadece bir kütüphanedir. Bunlar sadece normal değerler olduğu için tip sistemini basitleştirir - Java'da, kullanmayacağınız türler (örneğin, geri dönüş tipi) ve efektler (örn. throws
İfadeler) arasında ayrım yapmanız gerekir Maybe
. Aynı zamanda, diğer kullanıcı tanımlı türler gibi davranırlar - dile eklenmiş özel bir hata işleme koduna gerek yoktur.
Diğer bir galibiyet, functor ve monad'lar Maybe
/ Either
var olan, yani mevcut monad kontrol akış fonksiyonlarından (adil bir sayı olan) yararlanabilecekleri ve genel olarak diğer monadlarla birlikte iyi oynayabilecekleri anlamına geliyor.
Bu, bazı uyarılar olduğunu söyledi. Birincisi, kontrol edilmeyen istisnaları Maybe
ne Either
değiştirmez ne de değiştirir . Her bölmenin bir değer getirmesi çok acı verici olacağı için 0'a bölmek gibi şeylerle başa çıkmak için başka bir yol isteyeceksiniz .Maybe
Başka bir problem, birden fazla hata türünün geri dönüşüdür (bu sadece bunun için geçerlidir Either
). İstisnalarla, aynı işlevde herhangi bir farklı istisna türünü atabilirsiniz. ile Either
, sadece bir tür olsun. Alt yazarak ya da yapıcı olarak tüm farklı hata türlerini içeren bir ADT ile bunun üstesinden gelinebilir (bu ikinci yaklaşım genellikle Haskell'de kullanılan şeydir).
Yine de, hepsinden önemlisi Maybe
/ Either
yaklaşımını tercih ediyorum çünkü daha basit ve daha esnek buluyorum.
OpenFile()
Atar FileNotFound
veya NoPermission
veya TooManyDescriptors
vb. A Hiçbiri bu bilgiyi taşımaz.if None return None
stil ifadesi olmadan yığına kolayca göndermenizi sağlar .Hepsinden önemlisi, bir istisna ve Belki de monad'in farklı amaçları vardır - bir problemi belirtmek için bir istisna kullanılır, ancak bir Belki değildir.
"Hemşire, 5. odada bir hasta varsa , beklemesini isteyebilir misin?"
("eğer" a dikkat edin - bu, doktorun Belki bir monad beklediği anlamına gelir )
None
değerler sadece yayılan olabilir). 5. puanınız tek tür haktır… soru şu: hangi durumlar açıkça istisnai? Görünüşe göre, çok değil .
bind
test etmenin None
sözdizimsel bir ek yüke neden olmayacak şekilde yazabilirsiniz . Çok basit bir örnek, C # Nullable
operatörleri uygun şekilde aşırı yüklüyor. None
Türü kullanırken bile kontrol etmek gerekmez. Tabii ki kontrol hala yapılır (güvenlidir), fakat perde arkasında ve kodunuzu karıştırmaz. Aynısı bir anlamda (5) 'e itiraz etmemize itirazınız için de geçerlidir, ancak bunun her zaman geçerli olmayabileceği konusunda hemfikirim.
Maybe
olarak, bir monad olarak muamele etmenin bütün amacı yayılan None
örtük yapmaktır . Bu, None
verilen geri dönmek istiyorsanız None
, hiçbir özel kod yazmanıza gerek olmadığı anlamına gelir . Eşleşmen gereken tek zaman, özel bir şey yapmak istersen None
. Asla bir if None then None
çeşit ifadeye ihtiyacın yok .
null
tam olarak böyle (örneğin if Nothing then Nothing
) ücretsiz kontrol edersiniz çünkü Maybe
bir monad İçin bind ( >>=
) tanımında kodlanmıştır Maybe
.
Either
gibi davranan hata bilgilerini (örneğin ) taşıyabilecek bir monad yazabilirsiniz Maybe
. İkisi arasında geçiş yapmak aslında oldukça basittir çünkü Maybe
gerçekten özel bir durumdur Either
. (In Haskell, düşünebildiğim Maybe
olarak Either ()
.)
"Belki" istisnaların yerine geçmez. İstisnaların istisnai durumlarda kullanılması amaçlanmıştır (örneğin: bir db bağlantısı açılması ve db sunucusu olması gerektiği halde orada değildir). "Belki", geçerli bir değere sahip olabileceğiniz veya bulunmayacağınız bir durumu modellemek içindir; bir anahtar için bir sözlükten bir değer elde edersiniz: orada olabilir veya olmayabilir - bu sonuçların herhangi biri hakkında "istisnai" bir şey yoktur.
Tikhon'un cevabını ikinci olarak söyledim, ancak herkesin kaçırdığı çok önemli bir pratik nokta olduğunu düşünüyorum:
Either
Mekanizma hiç vida dişlerine bağlı değildir.Bugünlerde gerçek hayatta gördüğümüz bir şey, birçok zaman uyumsuz programlama çözümünün Either
hata işleme tarzının bir türünü benimsemesidir . Bu bağlantıların herhangi birinde ayrıntılı olarak açıklandığı gibi Javascript vaatlerini düşünün :
Vaat kavramı, bunun gibi asenkron bir kod yazmanıza izin verir (son bağlantıdan alınmıştır):
var greetingPromise = sayHello();
greetingPromise
.then(addExclamation)
.then(function (greeting) {
console.log(greeting); // 'hello world!!!!’
}, function(error) {
console.error('uh oh: ', error); // 'uh oh: something bad happened’
});
Temel olarak, söz bir nesnedir:
Temel olarak, dilin yerel istisna desteği, hesabınız birden fazla iş parçacığında gerçekleştiğinde işe yaramadığından, söz verilen bir uygulamanın bir hata işleme mekanizması sağlaması gerekir ve bunlar Haskell'in Maybe
/ Either
türlerine benzer monadlar olarak ortaya çıkar .
Haskell tip sistemi, kullanıcının a olasılığını kabul etmesini gerektirirken, Nothing
programlama dilleri çoğu zaman bir istisnanın yakalanmasını gerektirmez. Bu, derleme sırasında kullanıcının bir hata kontrolü yaptığını bileceğimiz anlamına gelir.
throws NPE
her imzaya ve catch(...) {throw ...}
her tek yöntem gövdesine bir ekleme yapmak zorunda kalacakları bakımından kontrol edilmesini istemezler . Ancak belki de aynı şekilde kontrol edilmek üzere bir pazar olduğuna inanıyorum.
Belki de monad temelde çoğu ana dilin "boş araç hatası" kontrolünü kullanmasıyla aynıdır (boş olanı kontrol etmesini gerektirmez hariç) ve büyük ölçüde aynı avantaj ve dezavantajlara sahiptir.
Maybe
yazarak sadece iki sayı ekleyebilirsiniz ve sonuç bir kez daha isteğe bağlı bir değerdir. a + b
None
Maybe
tip , ancak kullanarak Maybe
bir monad olarak çok daha zarif boş-imsi mantığını ifade verir sözdizimi şeker ekler.
İstisna işleme faktoring ve test için gerçek bir acı olabilir. Python'un katı "try ... catch" bloğu olmadan istisnaları yakalamanıza izin veren "with" sözdizimi sağladığını biliyorum. Fakat Java'da, örneğin, catch catch blokları büyük, tek parça, ayrıntılı veya son derece ayrıntılı ve kırılması zor. Bunun üzerine, Java, kontrol edilen ve kontrol edilmeyen istisnalar etrafındaki tüm gürültüyü ekler.
Bunun yerine, monadınız istisnalar yakalar ve onları monadik alanın bir özelliği olarak görür (bazı işlem anomalileri yerine), o zaman ne attığınıza veya yakaladığınıza bakmaksızın o alana bağladığınız işlevleri karıştırma ve eşleştirmede serbestsiniz.
Eğer, daha iyisi, monadınız istisnaların olabileceği koşulları önlerse (boş bir Çek'i Belki'ye itmek gibi), sonra daha da iyi. eğer ... o zaman faktörü denemek ve denemek çok ... çok daha kolaydır.
Gördüğüm kadarıyla Go, her bir işlevin döneceğini (cevap, hata) belirterek benzer bir yaklaşım izliyor. Bu, işlevi, çekirdek yanıt türünün bir hata bildirimi ve etkin bir şekilde yan basma fırlatma ve yakalama istisnaları ile süslendiği bir monad boşluğuna "kaldırma" ile aynıdır.