Ücretsiz monadlar nelerdir?


368

Terimin gördüğüm Ücretsiz Monad açılır her şimdi ve sonra bir süre, ama herkes sadece / kullanmak ne olduklarını bir açıklama vermeden bunları tartışmak gibi görünüyor. Peki: ücretsiz monadlar nelerdir? (Monad'lara ve Haskell temellerine aşina olduğumu söyleyebilirim, ancak kategori teorisi hakkında çok kaba bir bilgiye sahibim.)


12
Oldukça iyi bir açıklama burada haskellforall.com/2012/06/…
Roger Lindsjö

19
@Roger beni buraya getiren bir tür sayfa. Bana göre, bu örnek "Ücretsiz" adlı bir tür için bir monad örneği tanımlar ve hepsi bu kadar.
David

Yanıtlar:


295

Edward Kmett'in cevabı açıkçası harika. Ancak, biraz teknik. İşte belki daha erişilebilir bir açıklama.

Serbest monadlar, functorları monadlara dönüştürmenin genel bir yoludur. Yani, herhangi bir işlev f Free fverildiğinde bir monaddır. Bir çift fonksiyona sahip olmanız dışında bu çok yararlı olmaz

liftFree :: Functor f => f a -> Free f a
foldFree :: Functor f => (f r -> r) -> Free f r -> r

Bunlardan ilki monadınıza "girmenize" ve ikincisi size "çıkmanız" için bir yol sağlar.

Daha genel olarak, eğer X fazladan bir şeyler P olan bir Y ise, o zaman "serbest X" fazladan bir şey kazanmadan bir Y'den bir X'e ulaşmanın bir yoludur.

Örnekler: bir monoid (X), temel olarak bir işlem (eklemeyi düşünebilirsiniz) ve bazı kimliğe (sıfır gibi) sahip olduğunu söyleyen ekstra yapıya (P) sahip bir kümedir (Y).

Yani

class Monoid m where
   mempty  :: m
   mappend :: m -> m -> m

Artık hepimiz listeleri biliyoruz

data [a] = [] | a : [a]

Peki, tbildiğimiz her türden [t]bir monoid

instance Monoid [t] where
  mempty   = []
  mappend = (++)

ve böylece listeler setler üzerinde (ya da Haskell tiplerinde) “serbest monoid” dir.

Tamam, serbest monadlar aynı fikir. Bir functor alıp bir monad geri veriyoruz. Aslında, monadlar endofunktör kategorisinde monoid olarak görülebildiğinden, bir listenin tanımı

data [a] = [] | a : [a]

free monads'un tanımına çok benziyor

data Free f a = Pure a | Roll (f (Free f a))

ve örneğin, listeler Monadiçin Monoidörneğe benzerliği vardır

--it needs to be a functor
instance Functor f => Functor (Free f) where
  fmap f (Pure a) = Pure (f a)
  fmap f (Roll x) = Roll (fmap (fmap f) x)

--this is the same thing as (++) basically
concatFree :: Functor f => Free f (Free f a) -> Free f a
concatFree (Pure x) = x
concatFree (Roll y) = Roll (fmap concatFree y)

instance Functor f => Monad (Free f) where
  return = Pure -- just like []
  x >>= f = concatFree (fmap f x)  --this is the standard concatMap definition of bind

şimdi iki operasyonumuzu gerçekleştiriyoruz

-- this is essentially the same as \x -> [x]
liftFree :: Functor f => f a -> Free f a
liftFree x = Roll (fmap Pure x)

-- this is essentially the same as folding a list
foldFree :: Functor f => (f r -> r) -> Free f r -> r
foldFree _ (Pure a) = a
foldFree f (Roll x) = f (fmap (foldFree f) x)

12
Bu, daha önce gördüğüm "özgür" ün en iyi ulaşılabilir açıklaması olabilir. Özellikle "Genel olarak" ile başlayan paragraf.
John L

16
Bence "f" herhangi bir sayıda uygulanmış " Free f a = Pure a | Roll (f (Free f a))olarak bakmak ilginç Free f a = a + fa + ffa + .... Daha sonra concatFree(yani join) "f, a'ya herhangi bir sayıda uygulandı (f herhangi bir sayıda uygulandı)" alır ve iç içe yerleştirilmiş iki uygulamayı bir taneye daraltır. Ve >>="f, bir sayıya herhangi bir sayıda uygulandı" ve "a'dan (b'ye herhangi bir sayıda uygulandı) nasıl alınır" alır ve temel olarak ikincisini birincinin içindeki a'lara uygular ve yuvalamayı daraltır. Şimdi kendim anladım!
jkff

1
olduğu concatFreetemelde join?
rgrinberg

11
“İşte belki daha erişilebilir bir açıklama. […] Aslında, monadlar endo functors kategorisinde monoid olarak görülebildiğinden,… ”Yine de, bunun çok iyi bir cevap olduğunu düşünüyorum.
Ruud

2
<3 (eğer yönlendirmelidir "monads endo functors kategorisinde Monoids olarak görülebilir" stackoverflow.com/a/3870310/1306877 her haskeller o referansla ilgili bilmelidir çünkü!)
TLO

418

İşte daha da basit bir cevap: Monad, monadik bağlam daraltıldığında " olarak hesaplanan " bir şeydir join :: m (m a) -> m a( >>=olarak tanımlanabilir hatırlama x >>= y = join (fmap y x)). Monad'lar bağlamı ardışık bir hesaplama zinciri üzerinden şu şekilde taşırlar: çünkü serideki her noktada, önceki çağrıdan gelen bağlam bir sonraki ile daraltılır.

Bir serbest monad tüm tatmin Monad yasalar, ancak herhangi çöken (yani hesaplama) yapmaz. Sadece iç içe geçmiş bir dizi bağlam oluşturur. Böyle bir serbest monadik değer yaratan kullanıcı, bu iç içe geçmiş bağlamlarda bir şey yapmaktan sorumludur, böylece böyle bir kompozisyonun anlamı , monadik değer yaratılana kadar ertelenebilir.


8
Paragraflarınız Philip'in gönderisine gerçekten harika bir katkı sağlıyor.
David

20
Bu cevabı gerçekten çok beğendim.
danidiaz

5
Serbest monad, Monad tipi sınıfın yerini alabilir mi? Yani, sadece ücretsiz monad'ın dönüşünü ve bağlanmasını kullanarak bir program yazabilir ve daha sonra Mwybe veya List'i tercih ettiğim veya herhangi bir şeyi kullanarak sonuçlara katılabilir miyim, hatta bir / bağlı işlev çağrısı dizisinin birden fazla monadik görünümünü oluşturabilir miyim. Alt ve ihmali görmezden gelmek, yani.
Ocak'ta misterbee

2
Bu cevap yardımcı oldu, ancak sanırım NICTA kursunda 'katıl' ile tanışmamış olsaydım ve bana haskellforall.com/2012/06/… okuduğumda kafam karışırdı . Bu yüzden benim için anlama hilesi, batana kadar çok sayıda cevap okumak. (NICTA Referans: github.com/NICTA/course/blob/master/src/Course/Bind.hs )
Martin Capodici

1
bu cevap şimdiye kadarki en iyisidir
Curycu

142

Ücretsiz bir foo, tüm 'foo' yasalarını karşılayan en basit şeydir. Yani, bir foo olmak için gerekli yasaları tam olarak karşılar ve ekstra bir şey değildir.

Unutkan bir işlev, bir kategoriden diğerine geçerken yapının bir kısmını "unutan" işlevdir.

Verilen fanktorlar F : D -> Cve G : C -> Dderiz F -| G, Feşlenik bırakılır G, ya Gdoğru esleniktir Fforall a, b zaman: F a -> bizomorftur a -> G boklar uygun kategorilerdeki nereden geldiğini.

Resmi olarak, serbest bir işlev unutkan bir işleve bitişik bırakılır.

Ücretsiz Monoid

Daha basit bir örnekle başlayalım, ücretsiz monoid.

Bazı operatörler kümesi tarafından tanımlanan bir Monoid ele alalım T, bir ikili işlev birlikte bir çift elemana püre için f :: T → T → T, ve bir unit :: Tbir ilişkisel yasası ve kimlik kanunu var, öyle ki,: f(unit,x) = x = f(x,unit).

Bir functor yapabilirsiniz U(onlar harita sağlamak oklar olduğunu, monoid homomorfizmleri nerede Monoids kategorisinden unitiçin unitdiğer Monoid üzerinde ve anlam değiştirmeden diğer Monoid için haritalama önce ya da sonra oluşturabileceği) kategorisine (okların sadece işlev okları olduğu) ve işlem hakkında 'unutulan' unitve sadece taşıyıcı kümesini veren kümelerden oluşur .

Daha sonra, Fkümeler kategorisinden, bu işleve bitişik kalan monoidler kategorisine geri dönen bir işlev tanımlayabilirsiniz . Bu işlev, bir seti amonoid [a], nerede unit = []ve ile eşleyen işlevdir mappend = (++).

Şimdiye kadar sözde Haskell'deki örneğimizi gözden geçirmek için:

U : Mon  Set -- is our forgetful functor
U (a,mappend,mempty) = a

F : Set  Mon -- is our free functor
F a = ([a],(++),[])

O zaman göstermek Fücretsizdir, Uunutulmaz bir fontöre bitişik olduğunu , yani yukarıda belirttiğimiz gibi, şunu göstermeliyiz

F a → b izomorfik a → U b

şimdi, hedefin, okların monomorfizmalar olduğu monoidler Fkategorisinde Monolduğunu hatırlayın, bu yüzden bir monoid homomorfizmanın [a] → btam olarak bir fonksiyonla tanımlanabileceğini göstermemiz gerekir a → b.

Haskell'de, sadece listeler için uzmanlaştığında tipte olan Set(er, Hasktaklit ettiğimiz Haskell türleri kategorisi Set) olan tarafını çağırıyoruz .foldMapData.FoldableMonoid m => (a → m) → [a] → m

Bunun bir sıfat olmasıyla ortaya çıkan sonuçlar vardır. Özellikle unutursanız, ücretsiz olarak inşa ederseniz, tekrar unutun, tıpkı bir kez unuttuğunuz gibi ve bunu monadik birleşmeyi oluşturmak için kullanabiliriz. çünkü UFUF~ U(FUF)~ UFve biz gelen kimlik monoid homomorfizmasının geçirebilirsiniz [a]için [a]bizim birleşim tanımlayan isomorphism aracılığıyla, bir liste İzomorfizma olsun [a] → [a]türde bir fonksiyonudur a -> [a]ve bu sadece listeler için iade edilir.

Bu terimlerdeki bir listeyi şu şekilde açıklayarak bunların tümünü daha doğrudan oluşturabilirsiniz:

newtype List a = List (forall b. Monoid b => (a -> b) -> b)

Ücretsiz Monad

Yani bir şeydir Ücretsiz Monad ?

Daha önce yaptığımızla aynı şeyi yapıyoruz, okların monad homomorfizmaları olduğu monad kategorisinden okların doğal dönüşümler olduğu bir endofunktör kategorisine unutulmaz bir fonktör U ile başlıyoruz ve bitişik kalan bir fonktor arıyoruz. Buna.

Peki, bu genellikle kullanıldığı gibi bir serbest monad kavramı ile nasıl ilişkilidir?

Bir şeyin özgür bir monad olduğunu bilmek Free f, size bir monad homomorfizması Free f -> mvermenin doğal bir dönüşüm (functor homomorfizması) vermekle aynı şey (izomorfik) olduğunu söyler f -> m. Unutmayın F a -> bki a -> U b, F'nin U'ya bitişik kalması için F'nin izomorfik olması gerekir .

F, en azından hackage paketinde Freekullandığım tipe göre izomorfik free.

Ayrıca, ücretsiz liste için yukarıdaki koda daha sıkı bir şekilde benzeterek,

class Algebra f x where
  phi :: f x -> x

newtype Free f a = Free (forall x. Algebra f x => (a -> x) -> x)

Eşsiz Comonad'lar

Unutkan bir fontöre doğru bir şekilde bitişik olarak var olduğunu düşünerek benzer bir şey inşa edebiliriz. Eşsiz bir functor basitçe / sağa bitişiktir / unutkan bir functordur ve simetriyle, bir şeyin cofree bir comonad olduğunu bilmek, bir comonad homomorfizması w -> Cofree fvermenin doğal bir dönüşüm vermekle aynı şey olduğunu bilmekle aynıdır w -> f.


12
@PauloScardine, bu endişelenmen gereken bir şey değil . Benim sorum bazı gelişmiş veri yapısını anlamak ve belki de şu anda Haskell gelişiminde son teknolojiye bir göz atmak ilgiden geldi - Haskell'i şu ana kadar yazmanın ne olduğuna dair hiçbir şekilde gerekli veya temsil edici değil. (Ve bir kez daha, IO öğrenme aşamasını geçtikten sonra daha iyi olur)
David

8
@PauloScardine Haskell'de ücretsiz monadlarla bile verimli bir şekilde programlamak için yukarıdaki cevaba ihtiyacınız yoktur. Aslında, kategori kuramında bir geçmişi olmayan birine ücretsiz monad'a bu şekilde saldırmayı önermem. Operasyonel bir perspektiften bunun hakkında konuşmanın ve kategori teorisine dalmadan nasıl kullanılacağını bilmenin birçok yolu vardır. Ancak teoriye dalmadan nereden geldikleri sorusunu cevaplamam mümkün değil. Ücretsiz yapılar kategori teorisinde güçlü bir araçtır, ancak bunları kullanmak için bu arka plana ihtiyacınız yoktur.
Edward KMETT

18
@PauloScardine: Haskell'i etkili bir şekilde kullanmak ve hatta ne yaptığınızı anlamak için tam olarak hesaplamaya ihtiyacınız yoktur. Mathyness sadece eğlence ve kâr için kullanabileceğiniz ekstra bir iyilik olduğunda "bu dil mathy" den şikayet etmek biraz garip. Bunları çoğu zorunlu dilde elde edemezsiniz. Neden ekstralardan şikayet edesin? Sadece matematiksel olarak mantık ETMEYİ seçebilir ve ona yeni bir dil gibi yaklaşabilirsiniz.
Sarah

3
@Sarah: Haskell hakkında bilgisayar teorisi ve lambda hesap termleri üzerinde ağır olmayan bir belge veya IRC görüşmesi görmedim.
Paulo Scardine

11
@PauloScardine bu biraz OT sürükleniyor, ancak Haskell'in savunmasında: benzer teknik şeyler diğer tüm programlama dilleri için geçerlidir, sadece Haskell'in insanların gerçekten onlardan konuşmaktan hoşlanabilecek kadar güzel bir derlemesi vardır. X'in bir monad neden / nasıl olduğu birçok insan için ilginçtir, IEEE kayan nokta standardı hakkında tartışmalar değildir; her iki durum da çoğu insan için önemli değildir, çünkü sadece sonuçları kullanabilirler.
David

72

Free Monad (veri yapısı), Monoid'e (sınıf) Liste (veri yapısı) gibi Monad'a (sınıfa) aittir: Daha sonra içeriğin nasıl birleştirileceğine karar verebileceğiniz önemsiz bir uygulamadır.


Muhtemelen bir Monad'ın ne olduğunu ve her Monad'ın fmap+ join+ returnveya bind+ 'nın belirli bir (Monad yasasına uyan) uygulamasına ihtiyacı olduğunu biliyorsunuzdur return.

Diyelim ki bir Functor'unuz (bir uygulaması fmap) var, ancak geri kalanı çalışma zamanında yapılan değerlere ve seçimlere bağlı.

Bu, Functor'u (tip) öyle bir şekilde saran Serbest Monad (veri yapısı) kullanılarak yapılabilir, böylece joinbu functorların bir indirgemeden ziyade istiflenmesi olur.

Gerçek returnve joinkullanmak istediğiniz, şimdi azaltma işlevine parametre olarak verilebilir foldFree:

foldFree :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b
foldFree return join :: Monad m => Free m a -> m a

Türlerini açıklamak için, biz yerini alabilir Functor file Monad mve bile (m a):

foldFree :: Monad m => (a -> (m a)) -> (m (m a) -> (m a)) -> Free m a -> (m a)

8
Bu cevap bana ne için yararlı olabileceklerini anladığım izlenimini verdi.
David

59

Haskell ücretsiz monad, functorların bir listesidir. Karşılaştırmak:

data List a   = Nil    | Cons  a (List a  )

data Free f r = Pure r | Free (f (Free f r))

Pureile benzer Nilve Freebenzerdir Cons. Ücretsiz bir monad, değerlerin listesi yerine işlev listesi saklar. Teknik olarak, farklı bir veri türü kullanarak ücretsiz monadlar uygulayabilirsiniz, ancak herhangi bir uygulama, yukarıdaki veri izomorfik olmalıdır.

Soyut bir sözdizimi ağacına ihtiyacınız olduğunda ücretsiz monadları kullanırsınız. Serbest monadın temel işlevi, sözdizimi ağacının her adımının şeklidir.

Birinin zaten bağlı olduğu görevim , ücretsiz monadlarla soyut sözdizimi ağaçlarının nasıl oluşturulacağına dair birkaç örnek veriyor


6
Bir tanım yapmak yerine sadece bir benzetme yaptığınızı biliyorum, ancak ücretsiz bir monad kesinlikle hiçbir anlamda bir işlev listesine benzemez. Bir functors ağacına çok daha yakın.
Tom Ellis

6
Terminolojimin yanındayım. Örneğin, dizin çekirdekli paketimi kullanarak, liste monad'ı gibi davranan "serbest monad kavrayışları" tanımlayabilirsiniz, ancak değerler yerine işlevleri bağlarsınız. Ücretsiz bir monad, tüm Haskell kavramlarını functors kategorisine çevirirseniz, listelerin ücretsiz monadlar haline gelmesi anlamında functorların bir listesidir. Gerçek bir functors ağacı tamamen farklı bir şey haline gelir.
Gabriel Gonzalez

4
Monad'ın bir anlamda monoid kavramının sınıflandırılması olduğu konusunda haklısınız, bu nedenle serbest monadlar, serbest monoidlere, yani listelere benzer. Bu ölçüde kesinlikle haklısınız. Bununla birlikte, serbest bir monad değerinin yapısı bir liste değildir. Aşağıda detay verdiğim gibi bir ağaç .
Tom Ellis

2
@TomEllis Teknik olarak, yalnızca temel işleçiniz bir ürün işlevi ise bir ağaçtır. Temel işlev olarak bir toplam işlevine sahip olduğunuzda, bir yığın makinesine daha çok benzemektedir.
Gabriel Gonzalez

21

Bence basit bir somut örnek yardımcı olacaktır. Diyelim ki bir fonksiyoncumuz var

data F a = One a | Two a a | Two' a a | Three Int a a a

açıkça fmap. Daha sonra Free F ayapraklar tip ağaçların türüdür aolan düğümleri ile etiketlenir ve One, Two, Two've Three. One-nodların bir çocuğu vardır, Two- ve Two'-nodların iki çocuğu vardır ve Three-nodların üçü vardır ve ayrıca bir ile etiketlenmiştir Int.

Free Fbir monad. returneşleyen xdeğerle sadece bir yaprak ağaca x. t >>= fyaprakların her birine bakar ve onları ağaçlarla değiştirir. Yaprak değerine sahip olduğunda, yo yaprağı ağaç ile değiştirir f y.

Bir diyagram bunu daha açık hale getiriyor, ancak kolayca bir çizim yapmak için imkanım yok!


14
Sizin söylediğiniz şey, serbest monadın functorun şeklini almasıdır. Bu yüzden işlev ağaç benzeri (ürünler) ise, serbest monad ağaç gibidir; listeye benzer (toplamlar) ise, ücretsiz monad listeye benzer; eğer fonksiyona benzerse, serbest monad fonksiyona benzer; Bu bana mantıklı geliyor. Yani tıpkı ücretsiz bir monoidde olduğu gibi, her mappend uygulamasına tamamen yeni bir unsur yaratmaya devam ediyorsunuz; serbest monad'da functor'un her uygulamasını tamamen yeni bir eleman olarak görürsünüz.
Bartosz Milewski

4
Functor bir "toplam functor" olsa bile, sonuçta elde edilen serbest monad hala ağaç şeklindedir. Sonunda ağacınızda birden fazla tip düğüm bulunur: toplamınızın her bir bileşeni için bir tane. Eğer "toplam fonksiyonu" X -> 1 + X ise, o zaman gerçekten dejenere bir ağaç türü olan bir liste alırsınız.
Tom Ellis
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.