Her zamanki gibi, insanların kullandığı terminoloji tamamen tutarlı değil. Monadlardan ilham alan çeşitli kavramlar var ama kesinlikle konuşulmuyor - pek de değil. "İndeksli monad" terimi, böyle bir kavramı karakterize etmek için kullanılan terimlerin bir sayısıdır ("monadish" ve "parametreli monad" (onlar için Atkey'in adı) dahil). (İlgileniyorsanız bu tür bir başka kavram, dönüşün nötr olarak indekslendiği ve bağın indeksinde biriktiği, bir monoid tarafından indekslenen, Katsumata'nın "parametrik etki monad'ı" dır.)
Öncelikle çeşitleri kontrol edelim.
IxMonad (m :: state -> state -> * -> *)
Yani, bir "hesaplama" (veya "eylem", isterseniz, ancak "hesaplamaya" bağlı kalacağım) gibi görünüyor
m before after value
nerede before, after :: state
ve value :: *
. Buradaki fikir, öngörülebilir bir durum kavramına sahip harici bir sistemle güvenli bir şekilde etkileşim kurmanın yollarını yakalamaktır . Bir hesaplamanın türü, hangi durumun çalışması gerektiğini before
, hangi durumun after
çalışacağını ve (normal monadlarda olduğu gibi *
) value
hesaplamanın ne tür ürettiğini söyler .
Alışılagelmiş bitler ve parçalar *
-bilimi bir monad gibidir , -bilhassa state
domino oynamak gibidir.
ireturn :: a -> m i i a -- returning a pure value preserves state
ibind :: m i j a -> -- we can go from i to j and get an a, thence
(a -> m j k b) -- we can go from j to k and get a b, therefore
-> m i k b -- we can indeed go from i to k and get a b
Bu şekilde üretilen "Kleisli ok" kavramı (hesaplama sağlayan işlev)
a -> m i j b -- values a in, b out; state transition i to j
ve bir kompozisyon elde ederiz
icomp :: IxMonad m => (b -> m j k c) -> (a -> m i j b) -> a -> m i k c
icomp f g = \ a -> ibind (g a) f
ve her zaman olduğu gibi, yasalar bunu tam olarak sağlıyor ireturn
ve icomp
bize bir kategori veriyor
ireturn `icomp` g = g
f `icomp` ireturn = f
(f `icomp` g) `icomp` h = f `icomp` (g `icomp` h)
veya komedide sahte C / Java / her neyse,
g(); skip = g()
skip; f() = f()
{g(); h()}; f() = h(); {g(); f()}
Neden uğraşıyorsun? Etkileşim "kurallarını" modellemek. Örneğin, sürücüde bir dvd yoksa çıkaramazsınız ve içinde zaten varsa sürücüye bir dvd koyamazsınız. Yani
data DVDDrive :: Bool -> Bool -> * -> * where -- Bool is "drive full?"
DReturn :: a -> DVDDrive i i a
DInsert :: DVD -> -- you have a DVD
DVDDrive True k a -> -- you know how to continue full
DVDDrive False k a -- so you can insert from empty
DEject :: (DVD -> -- once you receive a DVD
DVDDrive False k a) -> -- you know how to continue empty
DVDDrive True k a -- so you can eject when full
instance IxMonad DVDDrive where -- put these methods where they need to go
ireturn = DReturn -- so this goes somewhere else
ibind (DReturn a) k = k a
ibind (DInsert dvd j) k = DInsert dvd (ibind j k)
ibind (DEject j) k = DEject j $ \ dvd -> ibind (j dvd) k
Bununla birlikte, "ilkel" komutları tanımlayabiliriz
dInsert :: DVD -> DVDDrive False True ()
dInsert dvd = DInsert dvd $ DReturn ()
dEject :: DVDrive True False DVD
dEject = DEject $ \ dvd -> DReturn dvd
diğerlerinin bir araya getirildiği ireturn
ve ibind
. Şimdi yazabilirim (ödünç alma- do
nota)
discSwap :: DVD -> DVDDrive True True DVD
discSwap dvd = do dvd' <- dEject; dInsert dvd ; ireturn dvd'
ama fiziksel olarak imkansız değil
discSwap :: DVD -> DVDDrive True True DVD
discSwap dvd = do dInsert dvd; dEject -- ouch!
Alternatif olarak, kişinin ilkel komutlarını doğrudan tanımlayabilir
data DVDCommand :: Bool -> Bool -> * -> * where
InsertC :: DVD -> DVDCommand False True ()
EjectC :: DVDCommand True False DVD
ve sonra genel şablonu somutlaştırın
data CommandIxMonad :: (state -> state -> * -> *) ->
state -> state -> * -> * where
CReturn :: a -> CommandIxMonad c i i a
(:?) :: c i j a -> (a -> CommandIxMonad c j k b) ->
CommandIxMonad c i k b
instance IxMonad (CommandIxMonad c) where
ireturn = CReturn
ibind (CReturn a) k = k a
ibind (c :? j) k = c :? \ a -> ibind (j a) k
Aslında, ilkel Kleisli oklarının ne olduğunu (bir "domino" nun ne olduğunu) söyledik, sonra bunların üzerine uygun bir "hesaplama dizisi" kavramı inşa ettik.
Her indekslenmiş monad için m
, "değişim yok diyagonal" m i i
bir monaddır, ancak genel m i j
olarak değildir. Dahası, değerler indekslenmez, ancak hesaplamalar indekslenir, bu nedenle indekslenmiş bir monad, başka bir kategori için somutlaştırılmış monad'ın olağan fikri değildir.
Şimdi, Kleisli ok tipine tekrar bakın
a -> m i j b
i
Başlamak için durumda olmamız gerektiğini biliyoruz ve herhangi bir devamın durumdan başlayacağını tahmin ediyoruz j
. Bu sistem hakkında çok şey biliyoruz! Bu riskli bir operasyon değil! DVD'yi sürücüye koyduğumuzda içeri girer! DVD sürücüsü, her komuttan sonra durumun ne olduğu konusunda herhangi bir söz sahibi değildir.
Ancak dünya ile etkileşime girerken bu genel olarak doğru değildir. Bazen kontrolü biraz başkasına vermeniz ve dünyanın istediğini yapmasına izin vermeniz gerekebilir. Örneğin, bir sunucuysanız, müşterinize bir seçenek sunabilirsiniz ve oturum durumunuz, onların seçtiği şeye bağlı olacaktır. Sunucunun "teklif seçimi" işlemi, sonuçtaki durumu belirlemez, ancak sunucu yine de devam edebilmelidir. Bu, yukarıdaki anlamda "ilkel bir komut" değildir, bu nedenle indekslenmiş monadlar, öngörülemeyen senaryoyu modellemek için o kadar iyi bir araç değildir .
Daha iyi bir araç nedir?
type f :-> g = forall state. f state -> g state
class MonadIx (m :: (state -> *) -> (state -> *)) where
returnIx :: x :-> m x
flipBindIx :: (a :-> m b) -> (m a :-> m b) -- tidier than bindIx
Korkunç bisküviler mi? Pek değil, iki nedenden dolayı. Çünkü Birincisi, bir monad nedir gibi oldukça fazla görünüyor olduğunu üzerinden bir monad, ama (state -> *)
yerine *
. İki, Kleisli ok türüne bakarsanız,
a :-> m b = forall state. a state -> m b state
Good Old Hoare Logic'te olduğu gibi, bir ön koşul a
ve son koşullu hesaplama türlerini elde edersiniz b
. Program mantığındaki iddiaların Curry-Howard yazışmalarını aşması ve Haskell tipi haline gelmesi yarım yüzyıldan kısa sürdü. Tipi returnIx
"atlamak" için Hoare Mantık kuraldır "sadece hiçbir şey yaparak, tutan herhangi sonşartı elde edebilirsiniz" diyor. Karşılık gelen kompozisyon, ";" için Hoare Mantığı kuralıdır.
bindIx
Tüm niceleyicileri koyarak türüne bakarak bitirelim.
bindIx :: forall i. m a i -> (forall j. a j -> m b j) -> m b i
Bunların forall
zıt kutupları var. Başlangıç durumunu i
ve i
son koşulla başlayabilecek bir hesaplamayı seçiyoruz a
. Dünya istediği herhangi bir ara durumu seçer j
, ancak bize sonradan koşulun b
geçerli olduğuna dair kanıt vermelidir ve bu tür herhangi bir durumdan b
tutunmaya devam edebiliriz. Böylece, sırayla, b
durumdan koşul elde edebiliriz i
. "Sonra" durumları kavramamızı bırakarak, öngörülemeyen hesaplamaları modelleyebiliriz .
Hem IxMonad
ve MonadIx
yararlıdır. Her iki model de interaktif hesaplamaların değişen duruma göre geçerliliği, sırasıyla öngörülebilir ve öngörülemez. Tahmin edilebilirlik, elde edebildiğiniz zaman değerlidir, ancak tahmin edilemezlik bazen hayatın bir gerçeğidir. Öyleyse umarım, bu cevap indekslenmiş monadların ne zaman işe yaramaya başladıklarını ve ne zaman duracaklarını tahmin ederek bazı göstergeler verir.
True
/False
Değerlerini tür bağımsız değişkenleri olarak nasıl iletebilirsinizDVDDrive
? Bu bir uzantı mı, yoksa boole'lar gerçekten burada mı?