Monad (fonksiyonel programlama) - Monad (functional programming) - Wikipedia

İçinde fonksiyonel programlama, bir monad programların yapılandırılmasına izin veren bir soyutlamadır genel olarak. Destekleyici diller soyutlamak için monadları kullanabilir Genelge kodu program mantığı tarafından gerekli. Monadlar bunu kendi veri tipi (her bir monad türü için belirli bir tür), belirli bir hesaplama biriyle birlikte prosedür değerlerini sarmak hiç monad içindeki temel tip (bir monadik değer) ve bir başkası oluşturma işlevleri monadik değerleri veren (denir monadik fonksiyonlar).[1]

Bu, monad'lerin potansiyel işleme gibi çok çeşitli sorunları basitleştirmesini sağlar tanımsız değerler (ile Olabilir monad) veya değerleri esnek, iyi biçimlendirilmiş bir liste (kullanmak Liste Bir monad ile, bir programcı karmaşık bir işlev dizisini kısa ve öz hale getirebilir. boru hattı yardımcı veri yönetimini soyutlayan, kontrol akışı veya yan etkiler.[1][2]

Hem monad kavramı hem de terim orijinal olarak kategori teorisi, bir monadın bir functor ek yapı ile.[a] 1980'lerin sonlarında ve 1990'ların başlarında başlayan araştırmalar, monadların birleşik, işlevsel bir model altında görünüşte farklı bilgisayar bilimi sorunları getirebileceğini ortaya koydu. Kategori teorisi, aynı zamanda, monad yasaları, herhangi bir monad tarafından karşılanması gereken ve kullanılabilir Doğrulayın monadik kod.[3][4]

Monadlar yaptığından beri anlambilim bir tür hesaplama için açıksa, uygun dil özelliklerini uygulamak için de kullanılabilirler. Gibi bazı diller Haskell, hatta çekirdeğinde önceden oluşturulmuş tanımlar sunar kütüphaneler genel monad yapısı ve ortak durumlar için.[1][5]

Genel Bakış

"Bir monad için M, bir tür değeri M a bir tür değerine erişime sahip olmayı temsil eder a monad bağlamında. "--C. A. McCann[6]

Bir monad, bir ile tanımlanır tip yapıcı M iki işlemle birlikte:

  • dönüş :: a -> M a (olarak da adlandırılır birim) herhangi bir tür değerini saran a içine monadik değer tip M a,
  • katılmak :: M (M a) -> M a (olarak da adlandırılır kompozisyon) türdeki herhangi bir sarılmış monadik değeri açan M (M a) basit bir monadik değer türüne M a.

Tür yapıcı M dahası bir functor yani sağlamak için fmap :: (a -> b) -> M a -> M b, süre dönüş ve katılmak aşağıda belirtilen doğal uyumluluk ilişkilerini sağlamalıdır.

Uygulamada, monadlar genellikle bağlamak bunun yerine operatör, infix gösterimi ile yazılmıştır >>=:

  • bağlama :: M a -> (a -> M b) -> M b monadik türü eşleyen M a monadik tipe M b tipte monadik bir işlev verilir a -> M b.

Aşağıdakilerden birini sağlamaya dikkat edin: bağlamak veya katılmak bir monad tanımlamak kesinlikle eşdeğerdir:

  • Haritalama a -> M b işlevsel olarak M a -> M (M b) ve katılmak M (M b) -e M b , bağlayıcı ma >> = f aracılığıyla kurtarıldı katılmak (fmap f ma).
  • Karşılıklı olarak, izin verme a = M b kimlik haritaları a = M b -e M b Böylece mmb'ye katıl olarak kurtarıldı mmb >> = id, id kimlik haritasıdır.

Kullanım

Monadlar, programcının bir işlem dizisine benzer bir dizi işlem oluşturmasına izin verir. boru hattı ile bağlamak ifadeleri birbirine zincirleyen operatörler. Bu tür diziler doğal olarak zorunlu dillerin davranışını yansıtır; burada her kod satırı, değişken bildirimler ve atamalar yoluyla sonunda değiştirilmiş bir yürütme bağlamını bir sonrakine geçiren bir talimattır.

yapmak Haskell'deki gösterim, örneğin, monadik kod blokları aşağıdaki gibi yazılmasına izin verir:

ana :: IO ()ana = yapmak isim <- hat almak                    - getLine :: IO Dizesi          putStrLn ("Selam " ++ isim ++ "!")    - putStrLn :: String -> GÇ ()

İçinde IO monad, yukarıdaki bağlama eşdeğerdir getLine >> = (putStrLn. hi) nerede merhaba name = "Merhaba" ++ name ++ "!". yazı yapmak kod blokları, zorunlu kodun okunabilirliğini ödünç almamızı sağlar. Kullanma bağlamak ancak saf işlevli ardışık düzenler yazmaya teşvik eder.

İşlem dizileri, monadların bilgisayar bilimine, durumların, yan etkilerin ve I / O işlemlerinin ele alınmasında en güçlü uygulaması gibi görünse de, kavram çok daha geneldir ve örneğin tarafından verilen çok sayıda basit örnek vardır. Liste ve Olabilir monadlar. Daha ince Okuyucu monad, tüm işlev türlerini açıklayan s -> a ortak bir kaynaktan s, başka bir kanonik örnek ve diğer birçok monad için yapısal bir modeldir. Durum ve IO.

Liste monad

Listeler bir monadın ilk örneğini sağlar. Bu nedenle, soyut tanımlarına rağmen, monadlar çoğu programlama dilinde ortak olan çok basit bir veri türü ile somutlaştırılmıştır.

İle [a] = Liste a tür öğelerine sahip listelerin türünü belirtir abirim ve kompozisyon Listetarafından tanımlanır:

  • birim :: a -> [a] herhangi bir değere atar x tip a singleton listesi [x] bu elementi içeren
  • katıl :: [[a]] -> [a] tür listelerinin bir listesini birleştirir [[a]] bunları düzleştirilmiş bir tür listesine katarak [a].

Büyük basitliğinden dolayı, liste monadı bir şekilde evrenseldir: bir birleştirici işlemle bileşimi bekleyen herhangi bir terim dizisini temsil edebilir.

Örneğin işlevi düşünün boru: [b -> b] -> b -> b, ardışık düzen olarak görülen işlevlerin bir listesini oluşturmak. İç içe geçmiş listeleri, oluşan alt süreçler için bir metafor olarak düşünürsek, ortaya çıkan zincirleme süreci oluşturmanın iki eşdeğer yolu vardır:

  • boru. (harita borusu) :: [[b -> b]] -> b -> b
  • boru. katıl :: [[b -> b]] -> b -> b

Bu eşdeğerlik, birliktelik nın-nin (.): içinde parantezler ihmal edilebilir (f. g). h = f. (g. h) = f. g. h, işlevlerin oluşturulma sırası önemli olmadığından. İle çalışmak Liste monad, kişinin bu özelliği tam olarak tanımasına ve yalnızca monadik tipteki değerleri işlemeye odaklanmasına izin verir. Listesi (b -> b), iç içe geçmiş listelerin doğal olarak monadik kompozisyon tarafından indirgendiği.

Gibi aritmetik işlemlerin sum :: [Num] -> Num ve prod :: [Num] -> Num ayrıca yukarıdaki örneğin basit varyasyonlarını sağlar. Bu gerçeğin bir sonucudur (Num, (+), 0), (Num, (*), 1), ve (b -> b, (.), id) tüm yaygın örneklerdir monoidler, yani bir birleşim yasasının tanımlandığı ve bir birimi olduğu alanlar. Bu basit yapılar akılda tutulmalıdır. Monadlar kendileri monoid kavramın bir soyutlamasıdır ve ne kadar ezoterik olursa olsun, bir monad, endofunctors kategorisindeki bir monoiddir.

Bir başka yaygın yorum Liste monad bir temsilidir alternatifler, görüntüleme [a] seçilen bir değer için olası sonuçların toplamı olarak a. Daha az doğal olmasına rağmen, bu, bağlamak elementwise işlev uygulamasından elde edilen listeleri birleştiren operatör:

  • bağlama :: [a] -> (a -> [b]) -> [b]

Bu resimde, bir süreç, herhangi bir tek unsurla ilişkilendirilir. a olası sonuçların bir listesi b, bağlama basitçe içindeki olası değerler listesinden numaralandırır a. Bu bakış açısı, listelerin yapısal sıralanmasını ayarlamak için daha uyarlanmış dili kullanır ve kaçırır. Bununla birlikte, monadik işlemleri anlamada yardımcı olabilir.

Örneğin aşağıdakileri düşünün Gücü ayarla işlev, belirli bir listenin tüm alt listelerini döndürür:

Gücü ayarla :: [a] -> [[a]]Gücü ayarla [] = [[]]Gücü ayarla (x:xs) = yapmak            ys <- Gücü ayarla xs       - ys :: [a]    [x:ys, ys]              - ya x koy ya da koyma

Onun yapmak blok uygulaması, eşdeğer powerset (x: xs) = powerset xs >> = ( ys -> [x: ys, ys]), ifadesini gösterirbağlamak.

Bir örnek: Belki

Monadlarla programlamayı motive etmek için, işte hızlı bir sözde kod örneği. Tanımlanmamış değerler veya işlemler, sağlam yazılımların hazırlaması ve zarif bir şekilde ele alması gereken belirli bir sorundur.

Bu hedefe doğru ilk adım, bir seçenek türü bu, bir değeri bir tür değer taşıyan T (T herhangi bir tür olabilir) veya değeri yoktur. Yeni tip aranacak Belki t ve bu türün değerleri, bir tür değeri içerebilir Tveya boş değer ol Hiçbir şey değil. Bir değer X tip T tanımlanmış olan ancak bağlamında kullanılan Olabilir Aranacak Sadece X. Bu, bir değişkenin tanımlanmış bir değer taşıdığı ve taşımadığı durumlar arasında ayrım yaparak karışıklığı önlemek için yapılır.

veri Olabilir T  =  Sadece T veya Hiçbir şey değil

Belki t türü saran bir "sarmalama" türü olarak anlaşılabilir T bir istisnanın nedeni hakkında hiçbir bilgi taşımamasına rağmen, yerleşik istisna işleme ile yeni bir türe dönüşür.

Aşağıdaki kodda, değişkenlerin önünde m tipe sahip Belki t bir tür için T. Örneğin, bir değişken mx bir değer içeriyorsa Sadece xdeğişken nerede x türü var T. λx → ... bir anonim işlev parametre ile x kimin tipi çıkarsanmış, ve ... işlev bileşimi Şebeke.

Diğer bir iyileştirme, bir işlevin basit kontrol edilen istisnalar Birlikte Olabilir tip kısa devre ve geri dönüyor Hiçbir şey değil bir adım başarısız olduğunda, ancak bir hesaplama başarılı olursa yorum yapmadan doğru değeri döndürür.

Ekleme işlevi Ekle, tam olarak bunu iki eklerken yapan Olabilir değerler, mx ve benim, şu şekilde tanımlanabilir:

 Ekle : (Olabilir Numara, Olabilir Numara)  Olabilir Numara Ekle(mx,benim) = ...     Eğer mx dır-dir Hiçbir şey değil sonra         ... Hiçbir şey değil     Başka Eğer benim dır-dir Hiçbir şey değil sonra         ... Hiçbir şey değil     Başka         ... Sadece (x + y)     son Eğer

İşleyen fonksiyonları yazma Olabilir değerler duruma göre yorucu olabilir ve ancak daha fazla işlev tanımlandıkça daha da artacaktır. Adımları birbirine zincirleme operasyonu, bunu hafifletmenin bir yoludur ve infix operatörü sevmek x >> = yHatta, her adımdan sonraki (muhtemelen tanımlanmamış) sonucun bir sonrakine beslenmesini sezgisel olarak temsil edebilir. Her sonuç teknik olarak diğerine eklendiğinden işleviancak operatör bir parametre için bir işlev alacaktır. Gibi Ekle zaten çıktı değerinin türünü belirtir, operatörü esnek tutmak ve girdilerinden farklı türlerde çıktı veren işlevleri kabul etmek zarar vermemelidir:

 >>= : (Olabilir T, T  Olabilir U)  Olabilir U (mx >>= f) = ...     Eğer mx dır-dir (Sadece x) sonra         ... f(x)    - f, Belki U türünde tanımlanmış bir değer döndürür     Başka         ... Hiçbir şey değil - f değer döndürmez     son Eğer

İle >>= mevcut, Ekle artık çok daha kompakt bir şey olarak yeniden tanımlanabilir:

 Ekle(mx,benim)  =  mx >>= λx -> (benim >>= λy -> Sadece (x + y))

Bu daha özlüdür, ancak biraz daha fazla analiz daha da güçlü bir şeyi ortaya çıkarır. Birincisi, tek rol Sadece oynuyor Ekle temel bir değeri aynı zamanda bir Olabilir değer. Nasıl olduğunu vurgulamak için Sadece hareketler temel değer üzerine sararak, bir işlev olarak da yeniden tanımlanabilir. eta şimdilik:

 eta : T  Olabilir T eta(x)  =  Sadece x

Büyük resim, bu iki işlevin >>= ve eta basitleştirmek için tasarlandı Ekle, ancak açıkça Ekle içinde hiç yol, sadece Olabilir Bu işlevler, aslında, herhangi bir değer ve işlev için geçerli olabilir. Olabilir temel değerlerin türlerinden bağımsız olarak yazın.Örneğin, burada kısa ve öz bir DEĞİL (Kleene's) operatörü üçlü mantık tanımsız değerleri otomatikleştirmek için de aynı işlevleri kullanan:

trinot : Olabilir Boole  Olabilir Booletrinot(mp)  =  mp >>= λp -> (eta  değil) p

Ortaya çıkıyor Olabilir birlikte yazın >>= ve etaDiğer monadlar farklı mantıksal süreçler içerirken ve bazılarının ekstra özellikleri olabilirken, hepsinin bu örneğin temel taslağını izleyen benzer üç bileşeni (doğrudan veya dolaylı olarak) olacaktır.[1][7]

Tanım

Yukarıdaki örnekte kullanılan, işlevsel programlamada bir monad için daha yaygın olan tanım, aslında bir Kleisli üçlü kategori teorisinin standart tanımından ziyade. Bununla birlikte, iki yapının matematiksel olarak eşdeğer olduğu ortaya çıkar, bu nedenle her iki tanım da geçerli bir monad verir. İyi tanımlanmış, temel türler verildiğinde T, Ubir monad üç bölümden oluşur:

Yine de bir monad olarak tam olarak nitelendirmek için, bu üç bölümün birkaç yasaya da uyması gerekir:

  • birim bir sol kimlik için bağlamak:
    birim (a) >> = λx → f (x) f (a)
  • birim aynı zamanda için bir hak kimliktir bağlamak:
    ma >> = λx → birim (x) anne
  • bağlamak esasen ilişkisel:[e]
    ma >> = λx → (f (x) >> = λy → g (y)) (ma >> = λx → f (x)) >> = λy → g (y)[1]

Cebirsel olarak bu, herhangi bir monadın her ikisinin de bir kategori oluşturduğu anlamına gelir ( Kleisli kategorisi ) ve a monoid functors kategorisinde (değerlerden hesaplamalara), ikili operatör olarak monadik kompozisyon ve birim kimlik olarak.[kaynak belirtilmeli ]

Kullanım

Monad modelinin değeri, yalnızca kodu yoğunlaştırmanın ve matematiksel akıl yürütmeye bir bağlantı sağlamanın ötesine geçer. programlama paradigması Bir geliştiricinin kullandığı monad modelini takip etmek, tamamen işlevsel programlama.Tarafından şeyleştirme belirli bir hesaplama türü, yalnızca bir monad değil Kapsüller bu hesaplama modelinin sıkıcı ayrıntıları, ancak bunu beyan edici yol, kodun netliğini iyileştirir. Monadik değerler, yalnızca hesaplanan değerleri değil, aynı zamanda hesaplanan değerleri açıkça temsil ettiğinden Etkilerimonadik bir ifade, içindeki değeri ile ikame edilebilir referans olarak şeffaf pozisyonlar, saf ifadelerin olabileceği gibi, birçok teknik ve optimizasyona yeniden yazma.[4]

Tipik olarak, programcılar kullanacaktır bağlamak monadik işlevleri bir diziye zincirlemek, bu da bazılarının monadları "programlanabilir noktalı virgül" olarak tanımlamasına yol açarak zorunlu diller ayırmak için noktalı virgül kullanır ifadeler.[1][5]Ancak, monadların gerçekte hesaplamalar sipariş etmediği vurgulanmalıdır; bunları merkezi özellikler olarak kullanan dillerde bile, daha basit işlev bileşimi, bir program içindeki adımları düzenleyebilir. monad'ın genel faydası, bir programın yapısını basitleştirmede ve geliştirmede yatar. endişelerin ayrılması soyutlama yoluyla.[4][9]

Monad yapı aynı zamanda benzersiz bir matematiksel ve Derleme zamanı varyasyon dekoratör modeli Bazı monadlar, işlevlere erişilemeyen fazladan verileri iletebilir ve hatta bazıları yürütme üzerinde daha hassas bir kontrol uygulayabilir, örneğin yalnızca belirli koşullar altında bir işlevi çağırır. etki alanı mantığı kazan plakası kodu önceden geliştirilmiş modüllere yüklerken, monadlar için bir araç olarak bile düşünülebilir. bakış açısına yönelik programlama.[10]

Monadlar için kayda değer bir diğer kullanım, yan etkileri izole etmektir. giriş çıkış veya değiştirilebilir durum, aksi takdirde tamamen işlevsel kodda. Tamamen işlevsel diller bile Yapabilmek Bu "saf olmayan" hesaplamaları, karmaşık bir işlev bileşimi karışımı yoluyla, monadlar olmadan uygulamaya ve devam eden stil (CPS) özellikle.[2]Bununla birlikte, monadlarla, bu yapı iskeletinin çoğu, esasen CPS kodundaki yinelenen her bir kalıbı alıp ayrı bir monad halinde bir araya getirerek soyutlanabilir.[4]

Bir dil varsayılan olarak monadları desteklemiyorsa, modeli uygulamak hala mümkündür, çoğu zaman çok fazla zorluk çekmeden. Kategori teorisinden programlama terimlerine çevrildiğinde, monad yapısı bir genel kavram ve doğrudan eşdeğer bir özelliği destekleyen herhangi bir dilde tanımlanabilir sınırlı polimorfizm Bir kavramın altta yatan türler üzerinde çalışırken operasyonel ayrıntılar hakkında agnostik kalma yeteneği güçlüdür, ancak monadların benzersiz özellikleri ve katı davranışları onları diğer kavramlardan ayırır.[11]

Başvurular

Belirli monadlarla ilgili tartışmalar, belirli bir monad belirli bir hesaplama biçimini temsil ettiğinden, genellikle dar bir uygulama problemini çözmeye odaklanacaktır.Bazı durumlarda, bir uygulama, kendi temel mantığı dahilinde uygun monadlar kullanarak üst düzey hedeflerini bile karşılayabilir.

İşte tasarımlarının kalbinde monad bulunan birkaç uygulama:

Tarih

Programlamadaki "monad" terimi aslında APL ve J tamamen işlevsel olma eğiliminde olan programlama dilleri. Bununla birlikte, bu dillerde, "monad", bir parametre alan bir işlevin kısaltmasıdır (iki parametresi "ikili" olan bir işlev, vb.).[17]

Matematikçi Roger Godement 1950'lerin sonlarında monad kavramını ilk formüle eden kişiydi (buna "standart yapı" adını verdi), ancak egemen olan "monad" terimi kategori kuramcı Saunders Mac Lane.[kaynak belirtilmeli ] Kullanılarak yukarıda tanımlanan form bağlamakAncak, ilk olarak 1965'te matematikçi tarafından tanımlanmıştır Heinrich Kleisli herhangi bir monadın bir olarak nitelendirilebileceğini kanıtlamak için ek iki (kovaryant) işlev arasında.[18]

1980'lerden başlayarak, bilgisayar bilimleri topluluğunda belirsiz bir monad modeli kavramı su yüzüne çıkmaya başladı. Philip Wadler, bilgisayar uzmanı John C. Reynolds 1970'lerde ve 1980'lerin başlarında, onun değerini tartışırken bunun birkaç yönünü tahmin etmişti. devam eden stil, biçimsel anlambilim için zengin bir kaynak olarak kategori teorisi ve değerler ve hesaplamalar arasındaki tür ayrımı.[4]Araştırma dili Opal 1990 yılına kadar aktif olarak tasarlanan G / Ç'yi de etkin bir şekilde monadik tipe dayandırdı, ancak bağlantı o sırada gerçekleştirilemedi.[19]

Bilgisayar bilimcisi Eugenio Moggi kategori teorisi monadını fonksiyonel programlamaya açıkça bağlayan ilk kişi oldu, 1989'da bir konferans makalesinde,[20] ardından 1991'de daha rafine bir dergi sunumu izlemiştir. Daha önceki çalışmalarda, birkaç bilgisayar bilimcisi kategori teorisini kullanarak lambda hesabı. Moggi'nin temel kavrayışı, gerçek dünya programının yalnızca değerlerden diğer değerlere bir işlev değil, daha ziyade oluşan bir dönüşüm olduğuydu. hesaplamalar bu değerler üzerine. Kategori-teorik terimlerle resmileştirildiğinde, bu, monadların bu hesaplamaları temsil eden yapı olduğu sonucuna götürür.[3]

Philip Wadler ve Simon Peyton Jones her ikisi de Haskell'in teknik özelliklerinde yer aldı. Haskell, özellikle G / Ç ile uzlaşmak için v1.2'ye kadar sorunlu bir "yavaş akış" modeli kullandı. tembel değerlendirme, daha esnek bir monadik arayüze geçene kadar.[21] Haskell topluluğu, monadları işlevsel programlamadaki birçok soruna uygulamaya devam edecek ve Haskell ile çalışan araştırmacılar sonunda monad modelini daha geniş bir yapı hiyerarşisine genelleştirdiler. uygulama işlevleri ve oklar.[kaynak belirtilmeli ]

İlk başta, monadlarla programlama büyük ölçüde Haskell ve türevleriyle sınırlıydı, ancak işlevsel programlama diğer paradigmaları etkilediğinden, birçok dil bir monad modeli (ismen olmasa da ruhu olarak) dahil etti. Formülasyonlar artık var Şema, Perl, Python, Raket, Clojure, Scala, F # ve ayrıca yeni bir ML standart.[kaynak belirtilmeli ]

Analiz

Monad örüntüsünün bir yararı, program mantığına dayanmak için matematiksel kesinlik getirmesidir. Monad yasaları yalnızca bir örneğin geçerliliğini kontrol etmek için kullanılmaz, aynı zamanda ilgili yapılardan (işlevler gibi) özellikler aracılığıyla alt tipleme.

Monad yasalarının doğrulanması

Dönüyor Olabilir Örneğin, bileşenlerinin bir monad oluşturduğu beyan edildi, ancak monad yasalarını karşıladığına dair hiçbir kanıt verilmedi.

Bu, özellikleri eklenerek düzeltilebilir. Olabilir genel yasaların bir tarafına, ardından cebirsel olarak diğer tarafa ulaşmak için bir eşitlikler zinciri inşa edin:

Kural 1:  eta (a) >> = f (x) ⇔ (Sadece a) >> = f (x) ⇔ f (a)
Kural 2:  ma >> = eta (x) ⇔ ma Eğer anne dır-dir (Sadece a) sonra            eta (a) ⇔ Sadece bir Başka                        veya            Hiçbir şey ⇔ Hiçbir şey eğer biterse
Kural 3:  (ma >> = f (x)) >> = g (y) ⇔ ma >> = (f (x) >> = g (y))        Eğer (ma >> = f (x)) dır-dir (Sadece B) sonra               Eğer anne dır-dir (Sadece a) sonra            g (ma >> = f (x)) (f (x) >> = g (y)) a Başka                                            Başka            Hiçbir şey eğer biterse                                          eğer biterseEğer anne dır-dir (Sadece a) ve f (a) dır-dir (Sadece B) sonra                             (g ∘ f) bir Aksi takdirde anne dır-dir (Sadece a) ve f (a) o zaman hiçbir şey                       Hiçbir şey değil Başka                       Hiçbir şey değil eğer biterse

Türetme functors

Bilgisayar biliminde daha nadir olmasına rağmen, kategori teorisi doğrudan kullanılabilir, bu da bir monad'ı iki ek doğal dönüşümler Başlangıç ​​olarak, bir yapı bir üst düzey işlev (veya "işlevsel") adlı harita functor olarak nitelendirmek için:

harita φ: (a → b) → (ma → mb)

Bununla birlikte, bu her zaman önemli bir sorun değildir, özellikle de bir monad önceden var olan bir işlevden türetildiğinde, bunun üzerine monad miras alır harita otomatik olarak. (Tarihsel nedenlerden dolayı bu harita onun yerine denir fmap Haskell'de.)

Bir monadın ilk dönüşümü aslında aynıdır birim Kleisli üçlüsünden, ancak yapıların hiyerarşisini yakından takip ederek ortaya çıkıyor birim karakterize eder uygulama görevlisi, bir monad ve bir temel işlevci arasındaki bir ara yapı. Uygulama bağlamında, birim bazen şu şekilde anılır saf ama yine de aynı işlevdir. Bu yapıda farklı olan şey kanundur birim tatmin etmelidir; gibi bağlamak tanımlı değil, kısıtlama açısından verilir harita yerine:

(birim ∘ φ) x ↔ ((harita φ) ∘ birim) x[22]

Uygulamalı işlevden monad'a son sıçrama, ikinci dönüşümle gelir: katılmak işlev (kategori teorisinde bu, genellikle adı verilen doğal bir dönüşümdür μ), monad'ın iç içe yerleştirilmiş uygulamalarını "düzleştirir":

katılmak (mma): M (M T) → M T

Karakteristik fonksiyon olarak, katılmak ayrıca monad yasalarının üç çeşidini de karşılamalıdır:[kaynak belirtilmeli ]

katıl ∘ (harita birleştirme) mmma ↔ (birleştirme ∘ birleştirme) mmma ↔ ma
birleştir ∘ (harita birimi) ma ↔ (birime katıl) ma ↔ ma
katılmak ∘ (harita haritası φ) mma ↔ ((harita φ) ∘ birleştirme) mma ↔ mb

Bir geliştiricinin doğrudan bir monad veya bir Kleisli üçlüsü tanımladığına bakılmaksızın, temel yapı aynı olacaktır ve formlar birbirinden kolayca türetilebilir:

(harita φ) ma ↔ ma >> = (birim ∘ φ)
katılmak (mma) ↔ mma >> = id
ma >> = f ↔ (birleştirme ∘ (harita f)) ma[23]

Başka bir örnek: Liste

karmaşık çok değerli kare ve küp kök fonksiyonlar olabilir bestelenmiş böylece altıncı kök fonksiyonunu üretirler. Girdi ve çıktı türlerini yöneten yapı ve farklı eylemleri oluşturan yapı, birlikte, monad listele.[24]
madde işareti simgesi • gösterir bağlamak Şebeke, z karmaşık bir sayıdır ve köşeli parantezler bir dizi ve: = 'anlamına gelirolarak tanımlanır ':
(fg)(z) := eklemek(harita(f,g(z)))asansör(f) = f° := birimf = fbirimsqrt°(z) == eklemek(harita(birim,sqrt(z)))= eklemek(harita(sqrt,birim(z)))sxrt(z) = (cbrt°•sqrt°)(z) == eklemek(harita(cbrt°,sqrt°(z)))
[şüpheli ]

Monad'ı listeleyin daha basit bir işlevden monad türetmenin nasıl kullanışlı olabileceğini doğal olarak gösterir.Birçok dilde, bir liste yapısı bazı temel özelliklerle birlikte önceden tanımlanmış olarak gelir. Liste tip yapıcı ve eklemek operatör (ile temsil edilir ++ infix gösterimi için) burada zaten verildiği varsayılır.

Bir listeye düz bir değer yerleştirmek de çoğu dilde önemsizdir:

birim (x) = [x]

Buradan, bir işlevi yinelemeli olarak uygulamak liste anlama için kolay bir seçim gibi görünebilir bağlamak ve listeleri tam bir monad haline getirmek. Bu yaklaşımın zorluğu, bağlamak bu durumda listelerin çıktısını alacak olan monadik işlevler bekler; daha fazla işlev uygulandıkça, iç içe geçmiş listelerin katmanları birikir ve temel bir kavrayıştan fazlasını gerektirir.

Ancak, herhangi bir basit tüm liste üzerinde işlev görür, başka bir deyişle harita, basittir:

(harita φ) xlist = [φ (x1), φ (x2), ..., φ (xn)]

Şimdi, bu iki prosedür zaten Liste Tam bir monad olarak nitelendirmek için, yalnızca doğru bir fikir katılmak tekrarlanan yapıyı düzleştirmek gerekir, ancak listeler için bu, değerleri içeren iç listeyi eklemek için bir dış listeyi açmak anlamına gelir:

join (xlistlist) = join ([xlist1, xlist2, ..., xlistn]) = xlist1 ++ xlist2 ++ ... ++ xlistn

Ortaya çıkan monad yalnızca bir liste değil, işlevler uygulandıkça kendini otomatik olarak yeniden boyutlandıran ve yoğunlaştıran bir listedir.bağlamak artık sadece bir formülle de türetilebilir ve daha sonra Liste monadik işlevlerden oluşan bir ardışık düzen aracılığıyla değerler:

(xlist >> = f) = birleştirme ∘ (harita f) xlist

Bu monadik liste için bir uygulama, kesin olmayan hesaplama.Liste bir algoritmadaki tüm yürütme yolları için sonuçları tutabilir, ardından hangi yolların hangi sonuçlara yol açtığını "unutmak" için her adımda kendini yoğunlaştırır (deterministik, kapsamlı algoritmalardan bazen önemli bir ayrım). Diğer bir fayda, kontrollerin monad içine gömülebilmesidir. ; belirli yollar, boru hattındaki işlevleri yeniden yazmaya gerek kalmadan, ilk başarısızlık noktalarında şeffaf bir şekilde budanabilir.[23]

İkinci bir durum Liste Shines beste yapıyor çok değerli işlevler Örneğin, ninci karmaşık kök bir sayı vermelidir n farklı karmaşık sayılar, ancak başka mDaha sonra bu sonuçların kökü alınır, son m • n değerler, ürünün çıktısıyla aynı olmalıdır m • ninci kök.Liste her adımın sonuçlarını düz, matematiksel olarak doğru bir listeye yoğunlaştırarak bu sorunu tamamen otomatikleştirir.[24]

Teknikler

Monadlar, program mantığını düzenlemenin ötesinde ilginç teknikler için fırsatlar sunar. Monadlar, yararlı sözdizimsel özellikler için zemin hazırlarken, yüksek seviyeli ve matematiksel yapıları önemli soyutlamayı mümkün kılar.

Sözdizimsel şeker yapmama

Kullanmasına rağmen bağlamak açıkça çoğu zaman mantıklıdır, birçok programcı emir ifadelerini taklit eden bir sözdizimini tercih eder ( yapmama Haskell'de, performans notasyonu içinde OCaml, hesaplama ifadeleri içinde F #,[25] ve anlamak için içinde Scala ). Bu sadece Sözdizimsel şeker monadik bir boru hattını bir kod bloğu; derleyici daha sonra bu ifadeleri sessizce temel işlevsel koda çevirecektir.

Çeviri Ekle işlevinden Olabilir Haskell içine bu özelliği iş başında gösterebilir. Monadik olmayan bir versiyonu Ekle Haskell'de şuna benzer:

Ekle mx benim =    durum mx nın-nin        Hiçbir şey değil -> Hiçbir şey değil        Sadece x  -> durum benim nın-nin                       Hiçbir şey değil -> Hiçbir şey değil                       Sadece y  -> Sadece (x + y)

Monadic Haskell'de, dönüş standart adı birimartı lambda ifadeleri açıkça işlenmelidir, ancak bu teknik özelliklerle bile Olabilir monad daha temiz bir tanım yapar:

Ekle mx benim =    mx >>= (\x ->        benim >>= (\y ->            dönüş (x + y)))

Do-notation ile bu, çok sezgisel bir sıraya daha da ayrılabilir:

Ekle mx benim = yapmak    x <- mx    y <- benim    dönüş (x + y)

İkinci bir örnek, Olabilir tamamen farklı bir dilde kullanılabilir: F #. Hesaplama ifadeleriyle, döndüren "güvenli bölme" işlevi Yok tanımsız bir işlenen için veya sıfıra bölme şu şekilde yazılabilir:

İzin Vermek readNum () =  İzin Vermek s = Konsol.ReadLine()  İzin Vermek sonuç,v = Int32.TryParse(s)  Eğer (sonuç) sonra Biraz(v) Başka Yokİzin Vermek secure_div =   olabilir {     İzin Vermek! x = readNum()    İzin Vermek! y = readNum()    Eğer (y = 0)     sonra Yok    Başka dönüş (x / y)  }

Derleme zamanında, derleyici bu işlevi dahili olarak daha yoğun bir zincir halinde "çözer". bağlamak aramalar:

olabilir.Gecikme(eğlence () ->  olabilir.Bağla(readNum(), eğlence x ->    olabilir.Bağla(readNum(), eğlence y ->      Eğer (y=0) sonra Yok Başka olabilir.Dönüş(x / y))))

Son bir örnek olarak, genel monad yasalarının kendileri bile notasyonla ifade edilebilir:

yapmak { x <- dönüş v; f x }            ==  yapmak { f v }yapmak { x <- m; dönüş x }              ==  yapmak { m }yapmak { y <- yapmak { x <- m; f x }; g y }  ==  yapmak { x <- m; y <- f x; g y }

Kullanışlı olsa da, geliştirici bu blok stilinin tamamen sözdizimsel olduğunu ve dışa doğru monadik (veya hatta monadik olmayan CPS) ifadelerle değiştirilebileceğini her zaman hatırlamalıdır. bağlamak Monadik boru hattını ifade etmek birçok durumda daha net olabilir ve hatta bazı işlevsel programlama savunucuları, blok stilinin acemilerin zorunlu programlamadan alışkanlıklarını devretmesine izin verdiğinden, varsayılan olarak kaçınılması ve yalnızca açıkça üstün olduğunda kullanılması gerektiğini iddia eder.[26][1]

Genel arayüz

Her monad, monad yasalarını karşılayan belirli bir uygulamaya ihtiyaç duyar, ancak bir dil içindeki diğer yapılarla veya standart deyimlerle ilişki gibi diğer yönler, tüm monadlar tarafından paylaşılır.Sonuç olarak, bir dil veya kütüphane, bir genel Monad ile arayüz işlev prototipleri, alt tipleme ilişkileri ve diğer genel gerçekler Geliştirmeye bir başlangıç ​​sağlamanın ve yeni bir monadın bir süper tipten (functor'lar gibi) özellikleri devralmasını garanti etmenin yanı sıra, bir monadın tasarımını arayüze göre kontrol etmek başka bir kalite kontrol katmanı ekler.[kaynak belirtilmeli ]

Operatörler

Monadik kod, operatörlerin akıllıca kullanılmasıyla genellikle daha da basitleştirilebilir. harita işlevsellik, ad-hoc monadik işlevlerden daha fazlası üzerinde çalıştığı için özellikle yararlı olabilir; monadik bir işlev önceden tanımlanmış bir operatöre benzer şekilde çalışması gerektiği sürece, harita anında kullanılabilir "asansör "monadik olana daha basit operatör.[f]Bu teknikle, tanımı Ekle -den Olabilir örnek şu şekilde damıtılabilir:

ekle (mx, benim) = harita (+)

Süreç tanımlanarak bir adım daha ileri götürülebilir. Ekle sadece için değil Olabilirama tamamı için Monad Bunu yaparak, yapı arayüzüyle eşleşen ve kendi arayüzünü uygulayan herhangi bir yeni monad harita hemen kaldırılmış bir sürümünü devralacak Ekle Gereken işlevde yapılacak tek değişiklik, tür imzasını genellemektir:

ekleyin: (Monad Numarası, Monad Numarası) → Monad Numarası[27]

Analiz için de yararlı olan başka bir monadik operatör, monadik kompozisyondur (infix olarak temsil edilir) >=> burada), monadik işlevlerin daha matematiksel bir tarzda zincirlenmesine izin verir:

(f> => g) x = (f (x) → mb) >> = g (y = b)

Bu operatörle, monad yasaları, bir kimliğin birlikteliğine ve varlığına uygunluğunun altını çizerek, yalnızca işlevler açısından yazılabilir:

(birim> => g) ↔ g (f> => birim) ↔ f (f> => g)> => h ↔ f> => (g> => h)[1]

Varyasyonlar

Matematiksel düzeyde, bazı monadlar özellikle hoş özelliklere sahiptir ve belirli problemlere benzersiz bir şekilde uyarlanmıştır.

Katkı maddesi monadları

Bir katkı maddesi monad ek bir kapalı, ilişkisel, ikili operatör ile donatılmış bir monaddır mplus ve bir kimlik öğesi altında mplus, aranan mzero.The Olabilir monad, katkı maddesi olarak kabul edilebilir. Hiçbir şey değil gibi mzero ve bir varyasyon VEYA operatör olarak mplus.Liste aynı zamanda boş liste ile bir katkı monadidir [] gibi davranmak mzero ve birleştirme operatörü ++ gibi mplus.

Sezgisel olarak, mzero temel bir türden değer içermeyen tek bir sarmalayıcıyı temsil eder, ancak aynı zamanda bir "sıfır" olarak kabul edilir ("bir" yerine), çünkü bir emici için bağlamak, geri dönüyor mzero monadik bir işleve bağlandığında, bu özellik iki taraflıdır ve bağlamak ayrıca geri dönecek mzero herhangi bir değer bir monadic'e bağlandığında sıfır fonksiyonu.

Kategori-teorik terimlerle, bir ilave monad, bir kez monadik fonksiyonlar üzerinde bir monoid olarak nitelendirilir. bağlamak (tüm monadların yaptığı gibi) ve tekrar monadik değerlerin üzerinden mplus.[28][g]

Ücretsiz monadlar

Bazen, bir monadın genel ana hatları yararlı olabilir, ancak hiçbir basit model bir monad veya diğerini önermez. özgür monad içeri gelir; olarak özgür nesne monadlar kategorisinde, monadik yapıyı, monad kanunlarının ötesinde herhangi bir özel kısıtlama olmaksızın temsil edebilir. serbest monoid öğeleri değerlendirme olmadan birleştirir, serbest bir monad, tip sistemini tatmin etmek için işaretçilerle zincirleme hesaplamalara izin verir, ancak başka türlü daha derin anlambilim uygulamaz.

Örneğin, tamamen aracılığıyla çalışarak Sadece ve Hiçbir şey değil işaretçiler, Olabilir monad aslında özgür bir monaddır. Liste Öte yandan monad, listeler hakkında fazladan, spesifik gerçekler getirdiği için özgür bir monad değildir ( eklemekSon bir örnek, yazım işaretleyicileri kullanan soyut bir serbest monaddır. birim ve bağlamak ve yinelemeli, doğrusal tipte bir kurucu:

yeni tip Serbest F (T) = Birim T veya Bağlama (F, Serbest F (T)) birimi (x) = Birim xmx >> = f = ... Eğer mx dır-dir Birim x sonra        ... f (x) Başka        ... Bağla (f, mx) eğer biterse

Ancak ücretsiz monadlar değil bu örnekteki gibi bağlantılı bir listeyle sınırlıdır ve diğer yapılar etrafında oluşturulabilir: ağaçlar.

Serbest monadların kasıtlı olarak kullanılması ilk başta pratik görünmeyebilir, ancak biçimsel yapıları özellikle sözdizimsel problemler için çok uygundur. Ücretsiz bir monad, daha sonra anlambilim bırakırken sözdizimi ve türü izlemek için kullanılabilir ve ayrıştırıcılarda ve tercümanlar sonuç olarak.[29]Diğerleri, bunları daha dinamik, operasyonel sorunlara da uyguladı. yinelemeler bir dil içinde.[30]

Comonads

Ekstra özelliklere sahip monadlar üretmenin yanı sıra, herhangi bir monad için, bir kişi ayrıca bir komonad.Monadik kod, bir anlamda, altta yatan değerlerden oluşturulan hesaplamaları temsil ediyorsa, komonadlar değerlere indirgenmeler olarak görülebilir. Monadik kod, bir anlamda, tamamen "paketten çıkarılamaz"; Bir değer bir monad içine sarıldığında, herhangi bir yan etkiyle birlikte orada karantinaya alınır (tamamen işlevsel programlamada iyi bir şey). Bazen bir sorun, komonadların açıkça modelleyebileceği bağlamsal verileri tüketmekle ilgilidir.

Teknik olarak, bir komonad, kategorik ikili basitçe aynı gerekli bileşenlere sahip olacağı anlamına gelen bir monadın, yalnızca tip imzalarının yönü ile ters. bağlamak-entrik monad tanımı, bir komonad şunlardan oluşur:

  • Bir tür oluşturucu W bu, yüksek dereceli türü işaretler W T
  • İkili birim, aranan counit burada, temel değeri komonaddan çıkarır:
counit (wa): W T → T
  • Tersine çevirme bağlamak (ayrıca temsil edilir =>>) bu uzatmakindirgeyici işlevler zinciri:
(wa = >> f): (W U, W U → T) → W T[h]

uzatmak ve counit aynı zamanda monad yasalarının ikililerini de karşılamalıdır:

counit ∘ ( (wa = >> f) → wb )  ↔ f (wa) → bwa = >> counit ↔ wawa ( (= >> f (wx = wa)) → wb (= >> g (wy = wb)) → wc )( wa (= >> f (wx = wa)) → wb ) (= >> g (wy = wb)) → wc

Monadlara benzer şekilde, comonadlar ayrıca bir ikili kullanarak functorlardan türetilebilir. katılmak:

  • çiftleme zaten komonadik bir değeri alır ve onu başka bir komonadik yapı katmanına sarar:
çift ​​(wa): W T → W (W T)

Gibi işlemler uzatmak tersine çevrilir, ancak bir komonad değil ters işlevler üzerinde hareket eder ve sonuç olarak, komonadlar hala işlev görür. harita, değil yardımcılar İle alternatif tanım çiftleme, counit, ve harita ayrıca kendi ortak yasalarına da saygı göstermelidir:

((harita kopyası) ∘ kopya) wa ↔ (kopya ∘ kopya) wa ↔ wwwa ((harita birliği) ∘ kopya) wa ↔ (ülke ∘ kopya) wa ↔ wa ((harita haritası φ) ∘ kopya) wa ↔ (kopya ∘ (harita φ)) wa ↔ wwb

Ve monadlarda olduğu gibi, iki form otomatik olarak dönüştürülebilir:

(harita φ) wa ↔ wa = >> (φ ∘ counit) wxduplicate wa ↔ wa = >> wx
wa = >> f (wx) ↔ ((harita f) ∘ kopya) wa

Basit bir örnek, Ürün comonad, which outputs values based on an input value and shared environment data.In fact, the Ürün comonad is just the dual of the yazar monad and effectively the same as the Okuyucu monad (both discussed below).Ürün ve Okuyucu differ only in which function signatures they accept, and how they complement those functions by wrapping or unwrapping values.

A less trivial example is the Stream comonad, which can be used to represent data streams and attach filters to the incoming signals with uzatmak.In fact, while not as popular as monads, researchers have found comonads particularly useful for akış işleme and modeling veri akışı programlama.[31][32]

Due to their strict definitions, however, one cannot simply move objects back and forth between monads and comonads.As an even higher abstraction, oklar can subsume both structures, but finding more granular ways to combine monadic and comonadic code is an active area of research.[33][34]

More examples

Identity monad

The simplest monad is the Identity monad, which just annotates plain values and functions to satisfy the monad laws:

newtype Id T  =  Tunit(x)    =  x(x >>= f)  =  f(x)

Kimlik does actually have valid uses though, such as providing a base case for recursive monad transformers.It can also be used to perform basic variable assignment within an imperative-style block.[ben][kaynak belirtilmeli ]

Koleksiyonlar

Any collection with a proper eklemek is already a free monoid, but it turns out that Liste is not the only Toplamak that also has a well-defined katılmak and qualifies as a monad.One can even mutate Liste into these other monadic collections by simply imposing special properties on eklemek:[j][kaynak belirtilmeli ]

ToplamakMonoid properties
ListeBedava
Sonlu çoklu setDeğişmeli
Sınırlı setCommutative and etkisiz
Sonlu permutationsNon-commutative and idempotent

IO monad (Haskell)

As already mentioned, pure code should not have unmanaged side effects, but that does not preclude a program from açıkça describing and managing effects.This idea is central to Haskell's IO monad, where an object of type IO a can be seen as containing the current state of the world outside the program, and computing a value of type a. A computation that computes no value – i.e., a procedure – has the type IO (), "computing" the dummy value ().When a programmer binds an IO value to a function, the function makes decisions based on that view of the world (input from users, files, etc.), then yields a monadic value reflecting the new world-state (program output).[21]

For example, Haskell has several functions for acting on the wider dosya sistemi, including one that checks whether a file exists and another that deletes a file.Their two type signatures are:

doesFileExist :: FilePath -> IO BoolremoveFile :: FilePath -> IO ()

The first is interested in whether a given file really exists, and as a result, outputs a Boolean value içinde IO monad.The second function, on the other hand, is only concerned with acting on the file system so the IO container it outputs is empty.

IO is not limited just to file I/O though; it even allows for user I/O, and along with imperative syntax sugar, can mimic a typical "Selam Dünya!" program:

ana :: IO ()ana = yapmak  putStrLn "Hello, world!"  putStrLn "What is your name, user?"  isim <- getLine  putStrLn ("Nice to meet you, " ++ isim ++ "!")

Desugared, this translates into the following monadic pipeline (>> in Haskell is just a variant of bağlamak for when only monadic effects matter and the underlying result can be discarded):

ana :: IO ()ana =  putStrLn "Hello, world!" >>  putStrLn "What is your name, user?" >>   getLine >>= (\isim ->    putStrLn ("Nice to meet you, " ++ isim ++ "!"))

Writer monad (JavaScript)

Another common situation is keeping a log file or otherwise reporting a program's progress.Sometimes, a programmer may want to log even more specific, technical data for later profil oluşturma veya hata ayıklama.The Writer monad can handle these tasks by generating auxiliary output that accumulates step-by-step.

To show how the monad pattern is not restricted to primarily functional languages, this example implements a yazar monad in JavaScript.First, an array (with nested tails) allows constructing the yazar type as a bağlantılı liste.The underlying output value will live in position 0 of the array, and position 1 will implicitly hold a chain of auxiliary notes:

sabit yazar = [değer, []];

Tanımlama birim is also very simple:

sabit birim = değer => [değer, []];

Sadece birim is needed to define simple functions that output yazar objects with debugging notes:

sabit kare = x => [x * x, [`${x} was squared.`]];sabit yarıya = x => [x / 2, [`${x} was halved.`]];

A true monad still requires bağlamak, ama için yazar, this amounts simply to appending a function's output to the monad's linked list:

sabit bağlamak = (yazar, dönüştürmek) => {    sabit [değer, günlük] = yazar;    sabit [sonuç, güncellemeler] = dönüştürmek(değer);    dönüş [sonuç, günlük.concat(güncellemeler)];};

The sample functions can now be chained together using bağlamak, but defining a version of monadic composition (called pipelog here) allows applying these functions even more succinctly:

sabit pipelog = (yazar, ...dönüşümler) =>    dönüşümler.azaltmak(bağlamak, yazar);

The final result is a clean separation of concerns between stepping through computations and logging them to audit later:

pipelog(birim(4), kare, yarıya);// Resulting writer object = [8, ['4 was squared.', '16 was halved.']]

Environment monad

An environment monad (also called a reader monad ve bir function monad) allows a computation to depend on values from a shared environment. The monad type constructor maps a type T to functions of type ET, nerede E is the type of the shared environment. The monad functions are:

The following monadic operations are useful:

Sor operation is used to retrieve the current context, while yerel executes a computation in a modified subcontext. As in a state monad, computations in the environment monad may be invoked by simply providing an environment value and applying it to an instance of the monad.

Formally, a value in an environment monad is equivalent to a function with an additional, anonymous argument; dönüş ve bağlamak are equivalent to the K ve S combinators, respectively, in the SKI birleştirici hesabı.

State monads

A state monad allows a programmer to attach state information of any type to a calculation. Given any value type, the corresponding type in the state monad is a function which accepts a state, then outputs a new state (of type s) along with a return value (of type t). This is similar to an environment monad, except that it also returns a new state, and thus allows modeling a değişebilir çevre.

tip Durum s t = s -> (t, s)

Note that this monad takes a type parameter, the type of the state information. The monad operations are defined as follows:

-- "return" produces the given value without changing the state.dönüş x = \s -> (x, s)-- "bind" modifies m so that it applies f to its result.m >>= f = \r -> İzin Vermek (x, s) = m r içinde (f x) s

Useful state operations include:

almak = \s -> (s, s) -- Examine the state at this point in the computation.koymak s = \_ -> ((), s) -- Replace the state.değiştirmek f = \s -> ((), f s) -- Update the state

Another operation applies a state monad to a given initial state:

runState :: Durum s a -> s -> (a, s)runState t s = t s

do-blocks in a state monad are sequences of operations that can examine and update the state data.

Informally, a state monad of state type S maps the type of return values T into functions of type , nerede S is the underlying state. dönüş ve bağlamak function are:

.

From the category theory point of view, a state monad is derived from the adjunction between the product functor and the exponential functor, which exists in any kartezyen kapalı kategori tanım olarak.

Continuation monad

Bir devam monad with return type R maps type T into functions of type . It is used to model continuation-passing style. The return and bind functions are as follows:

call-with-current-continuation function is defined as follows:

Program logging

The following code is pseudocode. Suppose we have two functions foo ve bar, with types

foo : int -> intbar : int -> int

That is, both functions take in an integer and return another integer. Then we can apply the functions in succession like so:

foo (bar x)

Where the result is the result of foo applied to the result of bar uygulanan x.

But suppose we are debugging our program, and we would like to add logging messages to foo ve bar.So we change the types as so:

foo : int -> int * dizibar : int -> int * dizi

So that both functions return a tuple, with the result of the application as the integer, and a logging message with information about the applied function and all the previously applied functions as the string.

Unfortunately, this means we can no longer compose foo ve bar, as their input type int is not compatible with their output type int * string. And although we can again gain composablility by modifying the types of each function to be int * string -> int * string, this would require us to add boilerplate code to each function to extract the integer from the tuple, which would get tedious as the number of such functions increases.

Instead, let us define a helper function to abstract away this boilerplate for us:

bağlamak : int * dizi -> (int -> int * dizi) -> int * dizi

bağlamak takes in an integer and string tuple, then takes in a function (like foo) that maps from an integer to an integer and string tuple. Its output is an integer and string tuple, which is the result of applying the input function to the integer within the input integer and string tuple. In this way, we only need to write boilerplate code to extract the integer from the tuple once, in bağlamak.

Now we have regained some composability. Örneğin:

bağlamak (bağlamak (x,s) bar) foo

Nerede (x,s) is an integer and string tuple.

To make the benefits even clearer, let us define an infix operator as an alias for bağlamak:

(>>=) : int * dizi -> (int -> int * dizi) -> int * dizi

So that t >>= f aynıdır bind t f.

Then the above example becomes:

((x,s) >>= bar) >>= foo

Finally, it would be nice to not have to write (x, "") every time we wish to create an empty logging message, where "" is the empty string.So let us define a new function:

dönüş : int -> int * dizi

Which wraps x in the tuple described above.

Now we have a nice pipeline for logging messages:

((dönüş x) >>= bar) >>= foo

That allows us to more easily log the effects of bar ve foo açık x.

int * string is analogous to a monadic value. bağlamak ve dönüş are analogous to the corresponding functions of the same name.In fact, int * string, bağlamak, ve dönüş form a monad.

Ayrıca bakınız

Alternatives for modeling computations:

  • Effect systems are a different way to describe side effects as types
  • Uniqueness types are a third approach to handling side-effects in functional languages

Related design concepts:

  • Aspect-oriented programming emphasizes separating out ancillary bookkeeping code to improve modularity and simplicity
  • Kontrolün tersine çevrilmesi is the abstract principle of calling specific functions from an overarching framework
  • Type classes are a specific language feature used to implement monads and other structures in Haskell
  • decorator pattern is a more concrete, ad-hoc way to achieve similar benefits in object-oriented programming

Generalizations of monads:

  • Applicative functors generalize from monads by keeping only birim and laws relating it to harita
  • Oklar use additional structure to bring plain functions and monads under a single interface
  • Monad transformers act on distinct monads to combine them modularly

Notlar

  1. ^ Due to the fact that functions on multiple serbest değişkenler are common in programming, monads as described in this article are technically what category theorists would call strong monads.[3]
  2. ^ Semantically, M is not trivial and represents an endofunctor üzerinde kategori of all well-typed values:
  3. ^ While a (parametrically polymorphic) function in programming terms, birim (often called η in category theory) is mathematically a doğal dönüşüm, which maps between functors:
  4. ^ bağlamak, on the other hand, is not a natural transformation in category theory, but rather an extension o asansörler a mapping (from values to computations) into a morphism between computations:
  5. ^ Açıkçası, bağlamak may not be formally associative in all contexts because it corresponds to application within lambda hesabı, not mathematics. In rigorous lambda-calculus, evaluating a bağlamak may require first wrapping the right term (when binding two monadic values) or the bind itself (between two monadic functions) in an anonymous function to still accept input from the left.[8]
  6. ^ Some languages like Haskell even provide a pseudonym for harita in other contexts called asansör, along with multiple versions for different parameter counts, a detail ignored here.
  7. ^ Algebraically, the relationship between the two (non-commutative) monoid aspects resembles that of a near-semiring, and some additive monads do qualify as such. However, not all additive monads meet the dağıtım laws of even a near-semiring.[28]
  8. ^ In Haskell, uzatmak is actually defined with the inputs swapped, but as currying is not used in this article, it is defined here as the exact dual of bağlamak.
  9. ^ In category theory, the Kimlik monad can also be viewed as emerging from adjunction of any functor with its inverse.
  10. ^ Category theory views these collection monads as adjunctions between the free functor and different functors from the kümeler kategorisi için category of monoids.

Referanslar

  1. ^ a b c d e f g h O'Sullivan, Bryan; Goerzen, John; Stewart, Don (2009). "Monads". Real World Haskell. Sebastopol, California: O'Reilly Media. chapter 14. ISBN  978-0596514983.
  2. ^ a b Wadler, Philip (Haziran 1990). Comprehending Monads. ACM Conference on LISP and Functional Programming. Nice, France. CiteSeerX  10.1.1.33.5381.
  3. ^ a b c Moggi, Eugenio (1991). "Notions of computation and monads" (PDF). Bilgi ve Hesaplama. 93 (1): 55–92. CiteSeerX  10.1.1.158.5275. doi:10.1016/0890-5401(91)90052-4.
  4. ^ a b c d e Wadler, Philip (Ocak 1992). The essence of functional programming. 19th Annual ACM Symposium on Principles of Programming Languages. Albuquerque, New Mexico. CiteSeerX  10.1.1.38.9516.
  5. ^ a b Hudak, Paul; Peterson, John; Fasel, Joseph (1999). "About Monads". A Gentle Introduction to Haskell 98. chapter 9.
  6. ^ C. A. McCann's answer (Jul 23 '10 at 23:39) How and why does the Haskell Cont monad work?
  7. ^ Spivey, Mike (1990). "A functional theory of exceptions" (PDF). Bilgisayar Programlama Bilimi. 14 (1): 25–42. doi:10.1016/0167-6423(90)90056-J.
  8. ^ "Monad laws". HaskellWiki. haskell.org. Alındı 14 Ekim 2018.
  9. ^ "What a Monad is not". 7 Ekim 2018.
  10. ^ De Meuter, Wolfgang (1997). Monads as a theoretical foundation for AOP (PDF). International Workshop on Aspect Oriented Programming at ECOOP. Jyväskylä, Finland. CiteSeerX  10.1.1.25.8262.
  11. ^ "Monad (sans metaphors)". HaskellWiki. 1 Kasım 2009. Alındı 24 Ekim 2018.
  12. ^ O'Sullivan, Bryan; Goerzen, John; Stewart, Don (2009). "Using Parsec". Real World Haskell. Sebastopol, California: O'Reilly Media. 16.Bölüm ISBN  978-0596514983.
  13. ^ Stewart, Don (17 May 2007). "Roll Your Own Window Manager: Tracking Focus with a Zipper". Control.Monad.Writer. Arşivlendi 20 Şubat 2018 tarihinde orjinalinden. Alındı 19 Kasım 2018.
  14. ^ Benton, Nick (2015). "Categorical Monads and Computer Programming" (PDF). London Mathematical Society Impact150 Stories. 1. Alındı 19 Kasım 2018.
  15. ^ Kiselyov, Olag (2007). "Delimited Continuations in Operating Systems". Modeling and Using Context. Springer Berlin Heidelberg. pages 291--302. ISBN  978-3-540-74255-5.
  16. ^ Meijer, Erik (27 March 2012). "Your Mouse is a Database". ACM Sırası. 10 (3). Alındı 19 Kasım 2018.
  17. ^ Iverson, Kenneth (September 1987). "A dictionary of APL". APL Quote Quad. 18 (1): 5–40. doi:10.1145/36983.36984. ISSN  1088-6826. Alındı 19 Kasım 2018.
  18. ^ Kleisli, Heinrich (1965). "Every standard construction is induced by a pair of adjoint functors" (PDF). American Mathematical Society'nin Bildirileri. 16 (3): 544–546. doi:10.1090/S0002-9939-1965-0177024-4. Alındı 19 Kasım 2018.
  19. ^ Peter Pepper, ed. (Kasım 1997). The Programming Language Opal (Technical report) (5th corrected ed.). Fachbereich Informatik, Technische Universität Berlin. CiteSeerX  10.1.1.40.2748.
  20. ^ Moggi, Eugenio (Haziran 1989). Computational lambda-calculus and monads (PDF). Fourth Annual Symposium on Logic in computer science. Pacific Grove, California. CiteSeerX  10.1.1.26.2787.
  21. ^ a b Peyton Jones, Simon L.; Wadler, Philip (Ocak 1993). Imperative functional programming (PDF). 20th Annual ACM Symposium on Principles of Programming Languages. Charleston, Güney Carolina. CiteSeerX  10.1.1.53.2504.
  22. ^ "Applicative functor". HaskellWiki. Haskell.org. 7 Mayıs 2018. Arşivlendi 30 Ekim 2018'deki orjinalinden. Alındı 20 Kasım 2018.
  23. ^ a b Gibbard, Cale (30 December 2011). "Monads as containers". HaskellWiki. Haskell.org. Arşivlendi 14 Aralık 2017'deki orjinalinden. Alındı 20 Kasım 2018.
  24. ^ a b Piponi, Dan (7 August 2006). "You Could Have Invented Monads! (And Maybe You Already Have.)". A Neighborhood of Infinity. Arşivlendi 24 Ekim 2018 tarihli orjinalinden. Alındı 16 Ekim 2018.
  25. ^ "Some Details on F# Computation Expressions". Alındı 9 Ekim 2018.
  26. ^ "Do notation considered harmful". HaskellWiki. Alındı 12 Ekim 2018.
  27. ^ Giles, Brett (12 August 2013). "Lifting". HaskellWiki. Haskell.org. Arşivlendi from the original on 29 January 2018. Alındı 25 Kasım 2018.
  28. ^ a b Rivas, Exequiel; Jaskelioff, Mauro; Schrijvers, Tom (July 2015). From monoids to near-semirings: the essence of MonadPlus and Alternative (PDF). 17th International ACM Symposium on Principles and Practice of Declarative Programming. Siena, Italy. CiteSeerX  10.1.1.703.342.
  29. ^ Swierstra, Wouter (2008). "Data types à la carte" (PDF). Functional Pearl. Fonksiyonel Programlama Dergisi. Cambridge University Press. 18 (4): 423–436. CiteSeerX  10.1.1.101.4131. doi:10.1017/s0956796808006758. ISSN  1469-7653.
  30. ^ Kiselyov, Oleg (May 2012). Schrijvers, Tom; Thiemann, Peter (eds.). Iteratees (PDF). International Symposium on Functional and Logic Programming. Bilgisayar Bilimlerinde Ders Notları. 7294. Kobe, Japan: Springer-Verlag. pp. 166–181. doi:10.1007/978-3-642-29822-6_15. ISBN  978-3-642-29822-6.
  31. ^ Uustalu, Tarmo; Vene, Varmo (July 2005). Horváth, Zoltán (ed.). The Essence of Dataflow Programming (PDF). First Summer School, Central European Functional Programming. Bilgisayar Bilimlerinde Ders Notları. 4164. Budapest, Hungary: Springer-Verlag. pp. 135–167. CiteSeerX  10.1.1.62.2047. ISBN  978-3-540-46845-5.
  32. ^ Uustalu, Tarmo; Vene, Varmo (June 2008). "Comonadic Notions of Computation". Teorik Bilgisayar Bilimlerinde Elektronik Notlar. Elsevier. 203 (5): 263–284. doi:10.1016/j.entcs.2008.05.029. ISSN  1571-0661.
  33. ^ Power, John; Watanabe, Hiroshi (May 2002). "Combining a monad and a comonad" (PDF). Teorik Bilgisayar Bilimleri. Elsevier. 280 (1–2): 137–162. CiteSeerX  10.1.1.35.4130. doi:10.1016/s0304-3975(01)00024-x. ISSN  0304-3975.
  34. ^ Gaboardi, Marco; Katsumata, Shin-ya; Orchard, Dominic; Breuvart, Flavien; Uustalu, Tarmo (September 2016). Combining Effects and Coeffects via Grading (PDF). 21st ACM International Conference on Functional Programming. Nara, Japan: Association for Computing Machinery. pp. 476–489. doi:10.1145/2951913.2951939. ISBN  978-1-4503-4219-3.

Dış bağlantılar

HaskellWiki references:

  • "All About Monads " (originally by Jeff Newbern) — A comprehensive discussion of all the common monads and how they work in Haskell; includes the "mechanized assembly line" analogy.
  • "Typeclassopedia " (originally by Brent Yorgey) — A detailed exposition of how the leading typeclasses in Haskell, including monads, interrelate.

Öğreticiler:

Interesting cases: