Neye bakıyorsunuz, atkey'in parameterised monad, şimdi daha yaygın olarak dizinli monad olarak bilinir.
class IFunctor f where
imap :: (a -> b) -> f i j a -> f i j b
class IFunctor m => IMonad m where
ireturn :: a -> m i i a
(>>>=) :: m i j a -> (a -> m j k b) -> m i k b
IMonad
tek hücreli benzeri şeylerin sınıfı m :: k -> k -> * -> *
tür k
ait türleri yönlendirilmiş grafik üzerinden yolları tarif olup. >>>=
, i
- j
için tür düzey durumunu j
- k
olarak alan bir hesaplama içine sokan bir hesaplama bağlar ve i
- k
için daha büyük bir hesaplama döndürür. ireturn
, tür düzeyinde durumu değiştirmeyen tek bir değerde saf bir değer elde etmenizi sağlar.
ben istemiyorum büyük nedeni türü için IMonad
örneği yazma anlamaya zorunda kalmak, istek-yanıt eylem bu tür yapısını yakalamak için endeksli ücretsiz monad kullanmak için gidiyorum kendim:
data IFree f i j a where
IReturn :: a -> IFree f i i a
IFree :: f i j (IFree f j k a) -> IFree f i k a
instance IFunctor f => IFunctor (IFree f) where
imap f (IReturn x) = IReturn (f x)
imap f (IFree ff) = IFree $ imap (imap f) ff
instance IFunctor f => IMonad (IFree f) where
ireturn = IReturn
IReturn x >>>= f = f x
IFree ff >>>= f = IFree $ imap (>>>= f) ff
Biz şu funktor gelen ücretsiz olarak Door
monad inşa edebilirsiniz:
data DoorState = Opened | Closed
data DoorF i j next where
Open :: next -> DoorF Closed Opened next
Close :: next -> DoorF Opened Closed next
Ring :: next -> DoorF Closed Closed next
instance IFunctor DoorF where
imap f (Open x) = Open (f x)
imap f (Close x) = Close (f x)
imap f (Ring x) = Ring (f x)
type Door = IFree DoorF
open :: Door Closed Opened()
open = IFree (Open (IReturn()))
close :: Door Opened Closed()
close = IFree (Close (IReturn()))
ring :: Door Closed Closed()
ring = IFree (Ring (IReturn()))
Sen open
bir cur neden olan bir kapı, can Açıkça kapanan kapı açık olmak üzere, close
bir açık kapı veya ring
kapalı bir kapın zili, muhtemelen evin sakinleri sizi görmek istemediğinden dolayı.
Son olarak, RebindableSyntax
dil uzantısı, standart Monad
sınıfını kendi özel IMonad
ile değiştirebileceğimiz anlamına gelir.
(>>=) = (>>>=)
m >> n = m >>>= const n
return = ireturn
fail = undefined
door :: Door Open Open()
door = do
close
ring
open
Ancak gerçekten monadın bağlayıcı yapısını kullanmıyor görüyoruz. Yapı taşlarınızın hiçbiri Open
, Close
veya Ring
hiçbiri bir değer döndürmez. Yani ne gerçekten ihtiyacınız şu basit tip hizalanmış liste olduğunu düşünüyorum türü:
data Path g i j where
Nil :: Path g i i
Cons :: g i j -> Path g j k -> Path g i k
Operasyonel olarak Path :: (k -> k -> *) -> k -> k -> *
bağlantılı bir listesi gibi, ama bir kez daha açıklayan bazı ekstra tip düzeyinde bir yapıya sahiptir düğümleri k
olan yönlendirilmiş bir grafikte yol. Listenin öğeleri g
kenarlarıdır. Nil
her zaman kendisine bir düğüm i
bir yolunu bulabileceğini söylüyor ve Cons
bin millik bir yolculuk tek bir adımla başlar hatırlatmaktadır: Eğer k
için j
den j
için i
bir kenar ve bir yol varsa, şunları yapabilirsiniz i
'dan k
'a yol yapmak için bunları birleştirin. Bu, türünde bir hizalanmış liste olarak adlandırılır, çünkü bir öğenin bitiş tipi bir sonraki başlangıç türüyle eşleşmelidir. g
ikili mantıksal ilişki ise o zaman Path g
onun dönüşlü geçişli kapatma yapıları Curry-Howard Caddesi'nin diğer tarafında
. Veya, kategorik olarak,,
g
grafiğinin
serbest kategorisi numaralı morfizm türüdür. Serbest kategorideki morfizmi oluşturmak, tipte hizalanmış listeleri ekleyerek sadece (çevrilir).
instance Category (Path g) where
id = Nil
xs . Nil = xs
xs . Cons y ys = Cons y (xs . ys)
Sonra Path
açısından Door
yazabilirsiniz: (Sana liste değişmezleri aşırı izin vermezRebindableSyntax
düşünmek gerçi)
data DoorAction i j where
Open :: DoorAction Closed Opened
Close :: DoorAction Opened Closed
Ring :: DoorAction Closed Closed
type Door = Path DoorAction
open :: Door Closed Opened
open = Cons Open Nil
close :: Door Opened Closed
close = Cons Close Nil
ring :: Door Closed Closed
ring = Cons Ring Nil
door :: Door Open Open
door = open . ring . close
Sen do
gösterimini alamadım, ama bina hesaplamaları (.)
ile, saf fonksiyonların sıralanması gibi görünüyor, ki zaten yaptığınız şey için oldukça iyi bir benzetme olduğunu düşünüyorum. Benim için endeksli monad kullanmak için ekstra bir beyin gücü (nadir ve değerli bir doğal kaynak) gerektirir. Daha basit bir yapı yapacağı zaman monadların karmaşıklığından kaçınmak daha iyidir.
Sadece duyduğum bir numara olmasına rağmen, [indeksli monad'lar] (http://stackoverflow.com/q/28690448/2751851) için arama yaptığınızdan şüpheleniyorum. – duplode
İsterseniz, her zaman gerçek bir 'Monad 'yapmak zorunda kalmadan' yapmak' için 'RebindableSyntax' kullanabilirsiniz. – Alec