Bir monad, endofunktörler kategorisinde sadece bir monoid, sorun nedir?


723

Aşağıdakileri ilk kim söyledi?

Bir monad, endofunktörler kategorisinde sadece bir monoid, sorun nedir?

Ve daha az önemli bir notta, bu doğru mu ve eğer öyleyse bir açıklama yapabilir misiniz (umarım çok fazla Haskell deneyimi olmayan biri tarafından anlaşılabilir)?


14
Bkz. "Çalışan Matematikçi Kategorileri"
Don Stewart

19
Haskell'de monad kullanmak için bunu anlamanız gerekmez. Pratik bir perspektiften, bazı yeraltı tesisatlarından geçerek “devlet” ini dolaşmanın akıllıca bir yoludur.
starblue

1
Bu mükemmel blog gönderisini de buraya eklemek istiyorum: stephendiehl.com/posts/monads.html Doğrudan soruyu cevaplamıyor, ancak bence Stephen Haskell'de kategorileri ve monad'ları birbirine bağlama konusunda mükemmel bir iş çıkarıyor. Yukarıdaki cevapları okuduysanız - bu, buna bakmanın iki yolunu birleştirmeye yardımcı olacaktır.
Ben Ford

3
Daha kesin olarak "Herhangi bir C kategorisi için, endofunktörlerinin [C, C] kategorisi, kompozisyon tarafından indüklenen monoidal bir yapıya sahiptir. [C, C] 'deki monoid bir nesne, C üzerindeki bir monaddır." - en.wikipedia.org/wiki/Monoid_%28category_theory%29 adresinden. Kategori teorisinde monad'ın tanımı için bkz. En.wikipedia.org/wiki/Monad_%28category_theory%29.

1
@Dmitry Bir işlev , kategoriler arasındaki bir işlevdir ve bazı kısıtlamalar iyi davranır . C kategorisindeki bir endofunktor, C'den kendisine sadece bir fonktordur. Data.Functor , Hask kategorisindeki endofunktörler için bir tip sınıftır . Bir kategori nesnelerden ve morfizmlerden oluştuğu için, bir işlevin her ikisini de eşlemesi gerekir. Data.Functor örneği için nesneler üzerindeki harita (haskell türleri) f'nin kendisidir ve morfizmler (haskell fonksiyonları) ile ilgili harita fmap'tır.
Matthijs

Yanıtlar:


797

Bu söz öbeği James Iry, kurgusal olarak Philip Wadler ile ilişkilendirdiği son derece eğlenceli Kısa, Eksik ve Çoğunlukla Yanlış Programlama Dilleri Tarihinden kaynaklanmaktadır.

Orijinal alıntı, Kategori Teorisinin temel metinlerinden biri olan Çalışan Matematikçi için Kategoriler'deki Saunders Mac Lane'den alınmıştır . Burada , tam olarak ne anlama geldiğini öğrenmek için muhtemelen en iyi yer olan bağlamda .

Ama, bıçaklayacağım. Orijinal cümle şudur:

Tümü, X'deki bir monad, X'in endofunktörleri kategorisinde sadece bir monoiddir, ürün x, endofunktörlerin ve kimlik endofunktörü tarafından belirlenen birimin bileşimi ile değiştirilir.

X burada bir kategori. Endofunctors (genellikle olduğu kendisine bir kategoriden fanktorlar olan tüm Functor ; - ama sapmak tiplerinin kategorisi çoğunlukla sadece bir kategori ile uğraşıyoruz çünkü bildiğim kadarıyla işlevsel programcılar ilgili olarak s). Ama " X üzerinde endofunktörler" kategorisi olan başka bir kategori hayal edebilirsiniz . Bu, nesnelerin endofunktör olduğu ve morfizmlerin doğal dönüşümler olduğu bir kategoridir.

Ve bu endofunktörlerden bazıları monad olabilir. Hangileri monad? Tam olarak belirli bir anlamda monoidal olanlar . Monad'lardan monoidlere doğru eşlemeyi hecelemek yerine (Mac Lane bunu umduğumdan çok daha iyi yaptığından), ilgili tanımlarını yan yana koyacağım ve karşılaştırmanıza izin vereceğim:

Bir monoid ...

  • Bir set, S
  • Bir işlem, •: S × S → S
  • S , e: 1 → S'nin bir elemanı

... bu yasalara uymak:

  • (a • B) • c = a • (b • C) hepsi için bir , b ve c de S
  • e • a = a • e = a , herkes için a içinde S

Bir monad ...

  • Bir endofunctor, T: X → X (Haskell'de, * -> *bir Functorörneği olan tür yapıcısı )
  • Doğal bir dönüşüm, μ: T × T → T , burada × functor bileşimi anlamına gelir ( μjoin Haskell olarak bilinir )
  • Doğal bir dönüşüm, bir → T: η , I ile ilgili kimlik endofunctor olan X ( η olarak bilinen returnHaskell)

... bu yasalara uymak:

  • μ ∘ Tμ = μ ∘ μT
  • μ ∘ Tη = μ ∘ ηT = 1 (kimlik doğal dönüşümü)

Biraz şaşırarak, bu tanımların her ikisinin de aynı soyut kavramın örnekleri olduğunu görebilirsiniz .


21
Programlama Dillerinin Kısa, Eksik ve Çoğunlukla Yanlış Tarihi makalesi için teşekkür ve teşekkürler. Oradan olabileceğini düşündüm. Gerçekten en büyük programlama mizah parçalarından biri.
Roman A. Taycher

6
@Jonathan: Bir monoidin klasik formülasyonunda, × setlerin kartezyen ürünü anlamına gelir. : Daha fazla burada okuyabilirsin en.wikipedia.org/wiki/Cartesian_product , ancak temel fikir unsuru olmasıdır S × T bir çift (s, t) , nereye s ∈ S ve T ∈ T . Dolayısıyla monoidal ürünün imzası •: S × S -> S bu bağlamda S'nin 2 elemanını girdi olarak alan ve başka bir S elemanını çıktı olarak üreten bir fonksiyon anlamına gelir .
Tom Crockett

12
@TahirHassan - Kategori teorisinin genelliğinde, setler yerine opak "nesneler" ile ilgileniriz ve bu yüzden "ögeler" in a priori nosyonu yoktur. Ancak , nesnelerin ayarlandığı ve okların işlev olduğu Set kategorisini düşünürseniz , herhangi bir S kümesinin öğeleri, herhangi bir tek öğeden S'ye ayarlanan işlevlerle bire bir yazışma içindedir. eleman e ait S , tam olarak bir işlevi vardır -> S 1: f , 1 herhangi bir eleman kümesidir ... (devamı)
Tom Crockett

12
@TahirHassan 1 elemanlı setlerin kendileri "terminal nesneleri" nin daha genel kategori-teorik kavramının uzmanlaşmalarıdır: bir terminal nesnesi, herhangi bir nesneden tam olarak bir ok bulunan bir kategorinin herhangi bir nesnesidir ( Bu 1-eleman setleri doğrudur Set ). Kategori teorisinde terminal nesnelerine basitçe 1 ; izomorfizme kadar benzersizdirler, bu yüzden onları ayırt etmenin bir anlamı yoktur. Şimdi herhangi bir S için " S öğelerinin" tamamen kategori-teorik bir açıklamasına sahibiz : bunlar sadece 1'den S'e kadar olan oklardır !
Tom Crockett

7
@TahirHassan - Bunu Haskell terimleriyle ifade etmek için S, bir tür ise, bir işlev yazarken yapabileceğiniz tek f :: () -> Sşeyin belirli bir tür terimini S(varsa "öğesi") seçip geri dönmesini düşünün. bu ... argümanla ilgili gerçek bir bilgi verilmedi, bu nedenle işlevin davranışını değiştirmenin bir yolu yok. Bu yüzden fher seferinde aynı şeyi döndüren sabit bir işlev olmalıdır. ()("Birim"), Hask kategorisinin terminal nesnesidir ve içinde yaşayan tam olarak 1 (ıraksak olmayan) değerin olması tesadüf değildir.
Tom Crockett

533

Sezgisel olarak, süslü matematik sözlüğünün söylediği şey şudur:

Monoid

Bir monoid nesneleri kümesidir, ve bunların bir araya için bir yöntemdir. İyi bilinen monoidler şunlardır:

  • ekleyebileceğiniz sayılar
  • birleştirebileceğiniz listeler
  • sendika kurabilirsin

Daha karmaşık örnekler de var.

Ayrıca, her monoid bir kimliğe sahiptir, yani başka bir şeyle birleştirdiğinizde hiçbir etkisi olmayan "no-op" elemanı:

  • 0 + 7 == 7 + 0 == 7
  • [] ++ [1,2,3] == [1,2,3] ++ [] == [1,2,3]
  • {} sendika {apple} == {apple} birliği {} == {apple}

Son olarak, bir monoid ilişkisel olmalı . (nesnelerin soldan sağa sırasını değiştirmediğiniz sürece, uzun bir kombinasyon dizesini istediğiniz şekilde azaltabilirsiniz) Ekleme tamam ((5 + 3) +1 == 5+ (3+ 1)), ancak çıkarma ((5-3) -1! = 5- (3-1)) değildir.

Monad

Şimdi, özel bir tür seti ve nesneleri birleştirmenin özel bir yolunu ele alalım.

Nesneler

Setinizin özel türden nesneler içerdiğini varsayalım: fonksiyonlar . Ve bu işlevlerin ilginç bir imzası vardır: Sayılara sayı veya dizelere dizeler taşımazlar. Bunun yerine, her işlev iki adımlı bir işlemde sayı listesine bir sayı taşır.

  1. 0 veya daha fazla sonucu hesapla
  2. Bu sonuçları bir şekilde tek bir cevapta birleştirin.

Örnekler:

  • 1 -> [1] (sadece girişi sarın)
  • 1 -> [] (girişi atın, hiçbir şeyi bir listeye sarın)
  • 1 -> [2] (girişe 1 ekleyin ve sonucu sarın)
  • 3 -> [4, 6] (girişe 1 ekleyin ve girişi 2 ile çarpın ve çoklu sonuçları sarın )

Nesneleri Birleştirme

Ayrıca, fonksiyonları birleştirme yöntemimiz özeldir. Fonksiyonu birleştirmenin basit bir yolu kompozisyon : Yukarıdaki örneklerimizi alalım ve her bir fonksiyonu kendisiyle oluşturalım:

  • 1 -> [1] -> [[1]] (girişi iki kez sarın)
  • 1 -> [] -> [] (girişi atın, hiçbir şeyi bir listeye iki kez sarın)
  • 1 -> [2] -> [UH-OH! ] (bir listeye "1 ekleyemeyiz!")
  • 3 -> [4, 6] -> [UH-OH! ] (1 liste ekleyemeyiz!)

Tip teorisine çok fazla girmeden, mesele, bir tamsayı elde etmek için iki tamsayıyı birleştirebilmenizdir, ancak her zaman iki işlev oluşturamaz ve aynı türde bir işlev elde edemezsiniz. ( A -> a tipi işlevler oluşturulur, ancak a-> [a] olmaz.)

Şimdi, fonksiyonları birleştirmenin farklı bir yolunu tanımlayalım. Bu işlevlerden ikisini birleştirdiğimizde, sonuçları "çift sarmak" istemiyoruz.

İşte yaptığımız şey. İki F ve G fonksiyonunu birleştirmek istediğimizde, bu işlemi takip ediyoruz ( bağlama adı verilir ):

  1. F'den "sonuçları" hesaplayın, ancak bunları birleştirmeyin.
  2. Her bir F sonucuna G'yi ayrı ayrı uygulayarak sonuçları toplayarak sonuçları toplayın.
  3. 2 seviyeli koleksiyonu düzleştirin ve tüm sonuçları birleştirin.

Örneklerimize geri dönelim, bu yeni "bağlama" işlevlerini kullanarak bir işlevi kendisiyle birleştirelim (bağlayalım):

  • 1 -> [1] -> [1] (girişi iki kez sarın)
  • 1 -> [] -> [] (girişi atın, hiçbir şeyi bir listeye iki kez sarın)
  • 1 -> [2] -> [3] (1 ekleyin, ardından 1 ekleyin ve sonucu sarın.)
  • 3 -> [4,6] -> [5,8,7,12] (girişe 1 ekleyin ve her iki sonucu da tutarak girişi 2 ile çarpın, ardından her iki sonuca da tekrar yapın ve son halini sarın sonuçları listeye ekler.)

Birleştirerek fonksiyonların Bu daha karmaşık bir yol olduğunu (eğer fantezi sarma şeyler yapıyor değilken tanımı yazısı ilişkisel nasıl aşağıdaki) ilişkisel.

Hepsini bir araya getirmek,

  • bir monad, işlevleri birleştirmenin (sonuçlarını) bir yol tanımlayan bir yapıdır,
  • bir monoidin nesneleri birleştirmenin bir yolunu tanımlayan bir yapı olduğuna benzer şekilde,
  • kombinasyon yönteminin çağrışımsal olduğu durumlarda,
  • ve herhangi ile kombine edilebilir özel bir 'Hayır-op' olduğu yerde bir şey sonuçlanması şey değişmemiş.

notlar

Sonuçları "sarmanın" birçok yolu vardır. Sonuç yoksa bir durum çubuğu ekleyebilir, bir günlük mesajı yazdırabilir vb. Dikkatinizi çekerken bir liste veya bir küme oluşturabilir veya ilk sonuç dışındaki tüm sonuçları atabilirsiniz.

Temel fikri sezgisel olarak ele almayı umarak tanımlarla biraz gevşek oynadım.

Monad'ımızın a -> [a] fonksiyonlarında çalıştığında ısrar ederek işleri biraz basitleştirdim . Aslında, monadlar a -> mb tipi fonksiyonlar üzerinde çalışırlar , ancak genelleme, ana içgörü olmayan bir teknik ayrıntıdır.


22
Bu, her monadın nasıl bir kategori oluşturduğuna dair güzel bir açıklama ( Kleisli kategorisi gösterdiğiniz şeydir - ayrıca Eilenberg-Moore kategorisi var). Ancak herhangi iki Kleisli oku oluşturamamanız a -> [b]ve c -> [d](bunu sadece b= ise yapabilirsiniz c) nedeniyle, bu bir monoid tanımlamaz. Aslında "monoid operatörü" olan fonksiyon kompozisyonundan ziyade tarif ettiğiniz düzleştirme işlemidir.
Tom Crockett

6
Bir monad'ı yalnızca bir türle sınırladıysanız, yani formun yalnızca Kleisli oklarına izin verdiyseniz a -> [a], bu bir monoid olacaktır (çünkü Kleisli kategorisini tek bir nesneye ve yalnızca bir nesnenin herhangi bir kategorisine indirirsiniz) tanımı gereği bir monoid!), ancak monad'ın tüm genelliğini yakalayamaz.
Tom Crockett

5
Son notta, a -> [a] 'nın sadece bir -> [] a olduğunu hatırlamak yardımcı olur. ([] sadece tür yapıcısıdır.) Ve böylece sadece -> mb olarak görülemez, aynı zamanda [] da Monad sınıfının bir örneğidir.
Evi1M4chine

8
Bu, monadların en iyi ve en somut açıklaması ve tam anlamıyla haftalarda karşılaştığım monoidlerin matematiksel arka planı. Monads, eller aşağı olduğunda her Haskell kitabında basılması gereken şey budur. Upvote! Belki de monad'ların, haskell'e koydukları her şeyi post içine saran parametreli tip sınıf örnekleri olarak gerçekleştirildiği bilgisini daha da alabilirsiniz. (En azından şimdiye kadar onları bu şekilde anladım. Yanlışsam beni düzeltin. Bkz. Haskell.org/haskellwiki/What_a_Monad_is_not )
Aralık'ta

1
Bu harika - başka birine açıklayabilecek kadar iyi anladığım tek açıklama bu ... Ama yine de bunun neden bir şey düşünmenin değerli bir yolu olduğunu anlamıyorum. :(
Adam Barnes

84

İlk olarak, kullanacağımız uzantılar ve kütüphaneler:

{-# LANGUAGE RankNTypes, TypeOperators #-}

import Control.Monad (join)

Bunlardan, RankNTypesaşağıdakiler için kesinlikle gerekli olan tek şey. Bir keresinde RankNTypesbazı insanların yararlı bulduklarına dair bir açıklama yazdım , bu yüzden buna değineceğim.

Aktaran Tom Crockett mükemmel cevabı elimizde:

Bir monad ...

  • Bir endofunctor, T: X -> X
  • Doğal bir dönüşüm, μ: T × T -> T , burada × functor bileşimi anlamına gelir
  • Doğal bir dönüşümü, η: ı -> T , I ile ilgili kimlik endofunctor olan X

... bu yasalara uymak:

  • μ (μ (T × T) × T)) = μ (T × μ (T × T))
  • μ (η (T)) = T = μ (T (η))

Bunu Haskell koduna nasıl çevirebiliriz? Doğal bir dönüşüm kavramı ile başlayalım :

-- | A natural transformations between two 'Functor' instances.  Law:
--
-- > fmap f . eta g == eta g . fmap f
--
-- Neat fact: the type system actually guarantees this law.
--
newtype f :-> g =
    Natural { eta :: forall x. f x -> g x }

Formun A tipi f :-> gbir işlev tipine benzer, ancak bunun yerine bir şekilde bunu düşünmenin fonksiyonu iki arasındaki türleri (tür *), bir olarak düşünmek morfizmalar ikisi arasında functors (türünün her * -> *). Örnekler:

listToMaybe :: [] :-> Maybe
listToMaybe = Natural go
    where go [] = Nothing
          go (x:_) = Just x

maybeToList :: Maybe :-> []
maybeToList = Natural go
    where go Nothing = []
          go (Just x) = [x]

reverse' :: [] :-> []
reverse' = Natural reverse

Temel olarak, Haskell'de doğal dönüşümler , tip değişkeninin arayan tarafından "erişilemez" olacağı f xşekilde bir türden başka bir türe fonksiyonlardır . Yani mesela,g xxsort :: Ord a => [a] -> [a] doğal bir dönüşüme dönüştürülemez, çünkü hangi türler oluşturabileceğimiz konusunda "seçici" olur a. Bunu düşünmek için sıklıkla kullandığım sezgisel bir yol şudur:

  • Bir işlev, bir şeyin içeriği üzerinde herhangi bir şeye dokunmadan çalışmanın bir yoludur. yapıya .
  • Doğal dönüşüm, içeriğe dokunmadan veya içeriğe bakmadan bir şeyin yapısı üzerinde çalışmanın bir yoludur .

Şimdi, bununla birlikte, tanımın maddelerini ele alalım.

İlk fıkra "bir endofunktor, T: X -> X " tir . Eh, FunctorHaskell'deki her insanın nesneleri "Hask kategorisi" olarak adlandırdığı, nesneleri Haskell tipi (tür *) olan ve morfizmleri Haskell fonksiyonları olan bir endofunktördür . Bu karmaşık bir ifadeye benziyor, ama aslında çok önemsiz bir ifade. Bunun anlamı, Functor f :: * -> *a'nın size f a :: *herhangi biri için bir tür ve herhangi birinden a :: *bir işlev oluşturma aracı vermesidir fmap f :: f a -> f b.f :: a -> b ve bu uymanızı funktoru yasaları.

İkinci madde: IdentityHaskell'deki (Platform ile birlikte gelir, böylece içe aktarabilirsiniz) functor şu şekilde tanımlanır:

newtype Identity a = Identity { runIdentity :: a }

instance Functor Identity where
    fmap f (Identity a) = Identity (f a)

Böylece Tom Crockett'in tanımından η: I -> T doğal dönüşümü herhangi bir Monadörnek için şu şekilde yazılabilir t:

return' :: Monad t => Identity :-> t
return' = Natural (return . runIdentity)

Üçüncü fıkra: Haskell'deki iki işlevin bileşimi şu şekilde tanımlanabilir (Platform ile birlikte gelir):

newtype Compose f g a = Compose { getCompose :: f (g a) }

-- | The composition of two 'Functor's is also a 'Functor'.
instance (Functor f, Functor g) => Functor (Compose f g) where
    fmap f (Compose fga) = Compose (fmap (fmap f) fga)

Böylece Tom Crockett'in tanımından elde edilen doğal dönüşüm μ: T × T -> T şöyle yazılabilir:

join' :: Monad t => Compose t t :-> t
join' = Natural (join . getCompose)

Bunun endofunktörler kategorisinde bir monoid olduğu ifadesi Compose(sadece ilk iki parametresine kısmen uygulanır) ilişkilendirici olduğu anlamına gelir ve bu Identityonun kimlik elemanıdır. Yani, aşağıdaki izomorfizmler geçerlidir:

  • Compose f (Compose g h) ~= Compose (Compose f g) h
  • Compose f Identity ~= f
  • Compose Identity g ~= g

Bunların kanıtlanması çok kolaydır Composeve Identityher ikisi de olarak tanımlanır newtypeve Haskell Raporları, semantiğini, newtypetanımlanan newtypeveri türü ile argümanın türü arasındaki veri izleyicisinin izomorfizmi olarak tanımlar . Örneğin, şunu kanıtlayalım Compose f Identity ~= f:

Compose f Identity a
    ~= f (Identity a)                 -- newtype Compose f g a = Compose (f (g a))
    ~= f a                            -- newtype Identity a = Identity a
Q.E.D.

Yeni Naturaltipte, (Functor f, Functor g)kısıtlamanın ne yaptığını anlayamıyorum . Açıklayabilir misiniz?
dfeuer

@dfeuer Gerçekten önemli bir şey yapmıyor.
Luis Casillas

1
@LuisCasillas Gerekli görmedikleri için bu Functorkısıtlamaları kaldırdım . Kabul etmiyorsanız, onları geri eklemekten çekinmeyin.
Lambda Fairy

Functor ürününün kompozisyon olarak alınmasının resmi olarak ne anlama gelebileceğini açıklayabilir misiniz? Özellikle, functor kompozisyonu için projeksiyon morfizmleri nelerdir? Benim tahminim, ürünün sadece F func F, F x F ve sadece jointanımlandığında functor için tanımlanmış olmasıdır. Ve bu joinprojeksiyon morfizmi. Ama emin değilim.
tksfz

6

Not: Hayır, bu doğru değil. Bir noktada, Dan Piponi'nin bu cevabı hakkında, buradaki neden ve etkinin tam tersi olduğunu söyleyen bir yorum vardı, makalesini James Iry'nin quipine yanıt olarak yazdı. Ancak, belki de bazı kompulsif düzenleyiciler tarafından kaldırılmış gibi görünüyor.

Aşağıda benim orijinal cevabım.


Bu Iry okumuştu oldukça mümkündür Monoids itibaren monad'ların için Dan Piponi (SIGFPE) kategorisinde teorisi ve "konulu endofunctors kategorisinde açık söz çok tartışma ile, Haskell Monoids gelen monads türediği bir yazı HASK ". Her halükarda, bir monadın endofunktör kategorisinde bir monoid olmasının ne anlama geldiğini merak eden herkes, bu türetmeyi okumaktan yararlanabilir.


1
"Belki de bir kompulsif düzenleyici tarafından" - ya da bu sitede sevgiyle bahsettiğimiz gibi bir moderatör :-).
halfer

6

Bu mesaja Mac Lane'nin Çalışan Matematikçi Kategorisi Teorisinin rezil teklifinin çıkarımını daha iyi anlayarak geldim .

Bir şeyin ne olduğunu tarif ederken, ne olmadığını tanımlamak genellikle eşit derecede faydalıdır.

Mac Lane'in açıklamayı bir Monad'ı tanımlamak için kullanması, monadlara özgü bir şeyi tanımladığı anlamına gelebilir. Benimle ayı. İfadesinin daha geniş bir anlayış geliştirmek için, ben onun olduğunu açıkça belirtmek gerekir inanıyoruz değil için, monadlara özgü bir şeyi tarif ; ifadede diğerleri arasında Uygulayıcı ve Oklar eşit olarak açıklanmaktadır. Aynı nedenle Int (Sum ve Product) üzerinde iki monoidimiz olabilir, endofunktörler kategorisinde X üzerinde birkaç monoidimiz olabilir. Ancak benzerliklerden daha fazlası da var.

Hem Monad hem de Uygulayıcı kriterleri karşılar:

  • endo => aynı yerde başlayan ve biten herhangi bir ok veya morfizm
  • functor => iki kategori arasındaki herhangi bir ok veya biçimsizlik

    (örneğin, günlük olarak Tree a -> List b, ancak Kategoride Tree -> List)

  • monoid => tek bir nesne; yani, tek bir tip, fakat bu bağlamda, sadece dış tabaka ile ilgili olarak; yani, Tree -> Listsadece sahip olamayız List -> List.

İfadede "Kategori ..." kullanılır. Bu ifadenin kapsamını tanımlar. Bir örnek olarak, Funktör Kategori kapsamını tanımlayan f * -> g *, yani, Any functor -> Any functorörneğin, Tree * -> List *ya da Tree * -> Tree *.

Kategorik bir ifadenin belirtmediği, bir şeye ve her şeye nerede izin verildiğini açıklar .

Bu durumda, functorların içinde * -> *aka a -> bbelirtilmez Anything -> Anything including Anything else. Hayal gücüm Int -> String'e atlarken, aynı zamanda, Integer -> Maybe Inthatta Maybe Double -> Either String Intnerede olduğunu da içerir a :: Maybe Double; b :: Either String Int.

Yani ifade şöyle bir araya geliyor:

  • işlev kapsamı :: f a -> g b (yani, herhangi bir parametreli türe herhangi bir parametreli tip)
  • endo + functor :: f a -> f b(yani, aynı parametreli türe herhangi bir parametreli tip) ... farklı dedi,
  • endofunctor kategorisinde bir monoid

Peki, bu yapının gücü nerede? Tam dinamikleri takdir etmek için, bir monoid'in (kimlik okuna benzeyen tek bir nesne) tipik çizimlerinin, herhangi bir sayıda monoid değeri :: single object -> single objectile parametreleştirilmiş bir oku kullanmama izin verdiğini gösteremediğini görmem gerekiyordu , adlı tek tip bir nesne Monoid izin. Eşdeğerlik endo, ~ kimlik oku tanımı , işlevin tür değerini ve en içteki "yararlı yük" katmanının türünü ve değerini göz ardı eder . Böylece denklik , işlev türlerinin eşleştiği herhangi bir durumda geri döner (örneğin, her ikisi de olduğu için eşdeğerdir ).trueNothing -> Just * -> NothingJust * -> Just * -> Just *Maybe -> Maybe -> Maybe

Kenar çubuğu: ~ dış kavramsal, ancak içinde en soldaki simgedir f a. Aynı zamanda "Haskell" in önce ne okuduğunu da açıklar (büyük resim); bu nedenle Tür, bir Tür Değerine göre "dış" tır. Programlamada katmanlar (bir referanslar zinciri) arasındaki ilişkinin Kategori içinde ilişkilendirilmesi kolay değildir. Küme Kategorisi, Functor Kategorisini (parametreleştirilmiş Türler) içeren Türleri (Int, Dizeler, Belki Int vb.) Tanımlamak için kullanılır. Referans zinciri: Functor Tipi, Functor değerleri (bu Functor kümesinin öğeleri, ör. Nothing, Just) ve sırayla, her functor değerinin işaret ettiği diğer her şey. Kategoride ilişki farklı tarif edilir, örneğin, return :: a -> m abir Functor'dan başka bir Functor'a, şimdiye kadar bahsedilenlerden farklı bir doğal dönüşüm olarak kabul edilir.

Sonuçta, herhangi bir tensör ürünü ve nötr bir değer için ana iş parçacığına geri dönersek, deyim paradoksal yapısından doğan şaşırtıcı derecede güçlü bir hesaplama yapısını tarif eder:

  • dışarıda tek bir nesne olarak görünür (ör. :: List ) ; statik
  • ama içeride çok fazla dinamiğe izin veriyor
    • herhangi bir arity fonksiyonuna yem ile aynı tipte herhangi bir sayıda değer (ör. Empty | ~ NonEmpty). Tensör ürünü, dış katman için herhangi bir sayıda girişi tek bir değere düşürecektir ...fold yük hakkında hiçbir şey söylemez)
    • sonsuz aralığı her iki en iç tabakasının tip ve değerler

Haskell'de ifadenin uygulanabilirliğinin açıklığa kavuşturulması önemlidir. Güç ve bu yapının yönlülüğü, bir monad ile hiçbir ilgisi yoktur haddi zatında . Başka bir deyişle, yapı bir monad'ı benzersiz kılan şeye dayanmaz.

Birbirine bağlı hesaplamaları, paralel olarak çalıştırılabilen hesaplamaları desteklemek için paylaşılan bir bağlamla kod oluşturup oluşturmayacağınızı anlamaya çalışırken, bu rezil ifade, açıkladığı kadarıyla, seçim arasında bir kontrast değildir. Uygulayıcı, Oklar ve Monadlar, aksine ne kadar aynı olduklarının bir açıklamasıdır. Eldeki karar için ifade tartışmalıdır.

Bu genellikle yanlış anlaşılır. Açıklama join :: m (m a) -> m a, monoidal endofunktor için tensör ürünü olarak tarif edilmektedir. Ancak, bu ifade bağlamında,(<*>) da seçilebileceğini . Gerçekten altı / yarım düzine bir örnektir. Değerleri birleştirme mantığı tam olarak aynıdır; aynı girdi, her biri için aynı çıktıyı üretir (Int için Sum ve Product monoidlerinin aksine, Ints birleştirilirken farklı sonuçlar üretir).

Özetlemek gerekirse: Endofunktör kategorisindeki bir monoid şunları açıklar:

   ~t :: m * -> m * -> m *
   and a neutral value for m *

(<*>)ve (>>=)her ikisi mde tek dönüş değerini hesaplamak için iki değere eşzamanlı erişim sağlar . Dönüş değerini hesaplamak için kullanılan mantık tamamen aynıdır. Onlar (parameterize fonksiyonların farklı şekillerde olmasaydı f :: a -> bkarşı k :: a -> m b(yani) ve hesaplama aynı dönüş türü ile parametrenin pozisyonuna a -> b -> bkarşı b -> a -> b, sanıyorum biz monoidal mantığı, parametreli olabilirdi her sırasıyla için) Her iki tanımda yeniden kullanım için tensör ürünü. Noktayı bir alıştırma olarak, denemek ve uygulamak ~tve ile bitirmek (<*>)ve (>>=)bunu tanımlamanız karar nasıl bağlı forall a b.

Son noktam minimum kavramsal olarak doğruysa, o zaman Uygulamalı ve Monad arasındaki kesin ve sadece hesaplama farkını açıklar: parametreleştirdikleri fonksiyonlar. Başka bir deyişle, farktır harici bu tip sınıfların uygulanmasına.

Sonuç olarak, kendi tecrübelerime göre, Mac Lane'nin rezil alıntısı, Haskell'de kullanılan deyimleri daha iyi anlamak için Kategori boyunca yolumu sürerken referans göstermem için bir rehber olan büyük bir "goto" meme sağladı. Haskell'de mükemmel bir şekilde erişilebilir hale getirilen güçlü bir hesaplama kapasitesinin kapsamını yakalamayı başarıyor.

Ancak, ifadenin monad dışındaki uygulanabilirliğini nasıl ilk yanlış anlamış olduğum ve burada aktardığımı umduğumda ironi var. Açıkladığı her şey, Uygulayıcı ve Monadlar (ve diğerleri arasında Oklar) arasında benzer olan şeydir. Söylemediği şey tam olarak aralarındaki küçük ama kullanışlı ayrımdır.

- E


5

Buradaki cevaplar hem monoidleri hem de monadları tanımlamakta mükemmel bir iş çıkarıyor, ancak yine de soruya cevap vermiyorlar:

Ve daha az önemli bir notta, bu doğru mu ve eğer öyleyse bir açıklama yapabilir misiniz (umarım çok fazla Haskell deneyimi olmayan biri tarafından anlaşılabilir)?

Burada eksik olan meselenin özü, daha kesin bir şekilde sınıflandırma olarak adlandırılan farklı bir "monoid" nosyonudur - monoidal bir kategoride monoiddir. Ne yazık ki Mac Lane'nin kitabının kendisi çok kafa karıştırıcı hale getiriyor :

XHerkesin söylediği gibi, bir monad , endofunctor kategorisinde sadece bir monoid X, ürünün ×yerine endofunktor ve kimlik endofunctor tarafından belirlenen ünite bileşimi getirildi.

Ana karışıklık

Bu neden kafa karıştırıcı? Çünkü "endofunktör kategorisinde monoid" in ne olduğunu tanımlamaz X. Bunun yerine, bu cümle, ikili işlem olarak functor bileşimi ve monoidal birim olarak kimlik functor ile birlikte tüm endofunktörler kümesinin içinde bir monoid almayı önermektedir . Mükemmel bir şekilde çalışır ve kimlik işlevini içeren ve işlev bileşimi altında kapalı olan herhangi bir endofunctor alt kümesine monoid dönüşür.

Ancak bu, kitabın o aşamada netleştiremediği doğru yorum değildir. Monad f, kompozisyon altında kapalı endofunktörlerin bir alt kümesi değil, sabit bir endofunktördür. Ortak bir yapı kullanmaktır fiçin oluşturmak tüm kümesi alarak Monoid kkat bileşimleri f^k = f(f(...))arasında folmak üzere kendisi ile, k=0kimliğine olduğu tekabül f^0 = id. Ve şimdi Sherkes için tüm bu güçlerin kümesi k>=0gerçekten de bir monoid "ürün x yerine endofunktörlerin bileşimi ve kimlik endofunktörü tarafından ayarlanan birim".

Ve henüz:

  • Bu monoid Sherhangi bir işlev için fya da kelimenin tam anlamıyla herhangi bir kendi haritası için tanımlanabilir X. Tarafından üretilen monoid f.
  • SFunctor bileşimi tarafından verilen monoidal yapının ve kimlik functorunun fmonad olması veya olmaması ile hiçbir ilgisi yoktur .

Ve işleri daha karmaşık hale getirmek için, "monoidal kategoride monoid" tanımı , içindekiler tablosundan görebileceğiniz gibi, daha sonra kitapta yer almaktadır . Yine de bu düşünceyi anlamak, monad'larla olan bağlantıyı anlamak için kesinlikle çok önemlidir.

(Katı) monoidal kategoriler

Monoidler için Bölüm VII'ye (Monads üzerinde Bölüm VI'dan sonra gelir), sözde katı monoidal kategorinin tanımını üçlü olarak buluruz(B, *, e) , burada Bbir kategori, *: B x B-> Bbir bifunctor (diğer bileşenlerin sabit olduğu her bileşene göre functor) ) ve ilişkilendirilebilirliği ve birim yasalarını karşılayan ebir birim nesnedir B:

(a * b) * c = a * (b * c)
a * e = e * a = a

herhangi bir nesne için a,b,cbir Bve her Morfizm aynı kimlik a,b,cile eile ikame id_ekimlik morfizma e. Şimdi, bizim durumumuzda, morfizm, functor kompozisyonu ve kimlik Bfunctoru olarak Xdoğal dönüşümlere sahip endofunktör kategorisinin nerede olduğunu, doğrudan doğrulanabileceği gibi, tüm bu yasaların karşılandığını gözlemlemek öğreticidir .*e

Kitapta bundan sonra gelenler , “rahat” monoidal kategorinin tanımlanmasıdır , burada yasalar sadece endofunktor kategorileriyle ilgili vakalarımız için önemli olmayan sözde tutarlılık ilişkilerini karşılayan bazı sabit doğal dönüşümleri modülo tutmaktadır.

Monoidal kategorilerde monoidler

Son olarak, Bölüm VII, bölüm 3 "Monoitler" de, gerçek tanım verilmiştir:

Bir monoid cbir monoidal kategoride (B, *, e)bir amacı, Biki oklarla (morfizimler)

mu: c * c -> c
nu: e -> c

3 diyagram değişmeli yapma. Bizim durumumuzda, bunların kesin olarak joinve returnbir monad için karşılık gelen doğal dönüşümler olan endofunktör kategorisindeki morfizmler olduğunu hatırlayın . Biz kompozisyon yaparken bağlantı oldukları daha iyi anlaşılır *yerine daha açık c * ctarafından c^2, nerede cbizim monad olduğunu.

Son olarak, 3 değişmeli diyagramın (monoidal kategoride bir monoid tanımında) genel (katı olmayan) monoidal kategoriler için yazıldığına dikkat çekerken, bizim durumumuzda monoidal kategorinin bir parçası olarak ortaya çıkan tüm doğal dönüşümler aslında kimliklerdir. Bu, diyagramları bir monad tanımındakiyle tamamen aynı hale getirecek ve yazışmayı tamamlayacak.

Sonuç

Özetle, herhangi bir monad, tanım gereği bir endofunktördür, bu nedenle endofunktör kategorisindeki bir nesne olup, monadic joinve returnoperatörler , bu (katı) monoidal kategoride bir monoid tanımını karşılar . Bunun tersine, endofunktörlerin monoidal kategorisindeki herhangi bir monoid, tanım gereği (c, mu, nu)bir nesne ve iki oktan oluşan bir üçlüdür , örneğin bizim durumumuzdaki doğal dönüşümler, bir monad ile aynı yasaları yerine getirir.

Son olarak, (klasik) monoidler ile monoidal kategorilerdeki daha genel monoidler arasındaki temel farka dikkat edin. İki ok muve nuüstü artık bir ikili işlem ve kümedeki bir birim değildir. Bunun yerine, sabit bir endofunktorunuz var c. Functor bileşimi *ve kimlik functor tek başına kitaptaki kafa karıştırıcı söze rağmen monad için gereken tam yapıyı sağlamaz.

Diğer bir yaklaşım, standart Monoid ile karşılaştırmak olacaktır Ckümesinin tüm öz haritaların Astandart kartezyen ürünü haritaya görülebilir ikili işlem bileşimi, C x Ciçine C. Kategorize monoid'e geçerek, kartezyen ürünü xfunctor bileşimi ile değiştiriyoruz *ve ikili işlem yerine doğal dönüşüm muile c * cdeğiştiriliyor c, yani joinoperatörlerin bir koleksiyonu

join: c(c(T))->c(T)

her nesne için T(programlama türü). Ve sabit bir nokta setinden haritaların görüntüleri ile tanımlanabilen klasik monoidlerdeki kimlik elemanları, returnoperatörlerin koleksiyonuyla değiştirilir

return: T->c(T) 

Ama şimdi artık kartezyen ürünler yok, bu yüzden çift element ve dolayısıyla ikili işlem yok.


Peki sorunun "bu doğru mu" kısmına cevabınız nedir? Bir monadın endofunktör kategorisinde bir monoid olduğu doğru mu? Ve eğer evet ise, bir monoid ve bir cebirsel monoid (teorik çarpım ve bir birim içeren bir küme) kategorisi teorisi kavramı arasındaki ilişki nedir?
Alexander Belopolsky
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.