2010-08-20 12 views
12

Wadler'in kâğıt üzerindeki kağıdını okuduktan (ve bazı bölümlerini gözden geçirdikten sonra), daha yakından tanımlayarak, tanımladığı monadların her biri için klavyeyi ve uygulama örneklerini tanımlamaya karar verdim.Haskell Eyaletindeki Eğlence/Uygulama Örnekleri

type M a = State -> (a, State) 
type State = Int 

bakınız, Wadler durum monad tanımlamak için kullanır tipi eşanlamlı kullanarak, aşağıdaki sahiptir (kullanarak ilgili isimleri bu yüzden daha sonra bir newtype beyanı ile tanımlayabilir).

fmap' :: (a -> b) -> M a -> M b 
fmap' f m = \st -> let (a, s) = m st in (f a, s) 

pure' :: a -> M a 
pure' a = \st -> (a, st) 

(<@>) :: M (a -> b) -> M a -> M b 
sf <@> sv = \st -> let (f, st1) = sf st 
         (a, st2) = sv st1 
        in (f a, st2) 

return' :: a -> M a 
return' a = pure' a 

bind :: M a -> (a -> M b) -> M b 
m `bind` f = \st -> let (a, st1) = m st 
         (b, st2) = f a st1 
        in (b, st2) 

bir newtype bildiriminde bir tip kurucu kullanılarak geçiş, örneğin,

newtype S a = S (State -> (a, State)) 

her ayrı düşer. Her şey

instance Functor S where 
fmap f (S m) = S (\st -> let (a, s) = m st in (f a, s)) 

instance Applicative S where 
pure a = S (\st -> (a, st)) 

ancak hiçbir şey nedeniyle lambda ifadesi bu tür kurucusu içine gizlenmiş gerçeğine ghc çalışır, örneğin, sadece hafif bir değişiklik. Şimdi gördüğüm tek çözüm bir işlev tanımlamaktır:

örneğin bir değeri 'st' olarak s bağlamak ve aslında dönmek için, içinde
isntThisAnnoying s (S m) = m s 

,

fmap f m = S (\st -> let (a, s) = isntThisAnnoying st m in (f a, s)) 

bunu yapmanın başka bir yolu var mı Bu yardımcı fonksiyonları kullanmaz? Eğer here bakarsak

cevap

11

, onlar bu şekilde tanımlamak göreceksiniz: iç lambda bir ad vermek için

newtype State s a = State { runState :: (s -> (a,s)) } 

böylece.

+2

Ayrıca, 'runState = flip isntThisAnnoying' anlamına gelir. – kennytm

+1

Tamam - yardımcı bir fonksiyona hala ihtiyaç duyulurken, sadece bir kayıt kullanarak, işlevi serbest olarak tanımlayabiliyordum. Ne diyorsun, o zaman, 'runState' veya 'run' gibi işlevlerden kaçınmanın bir yolu yoktur. Teşekkürler. – danportin

+0

Eğer onu bir işlev olarak düşünmek sizi incitirse, bunun yerine bir yapısal alan erişimcisi olarak düşünün. :-) –

4

Her zamanki yol, newtype newtype S a = S {runState : State -> (a, State)} tanımlamaktır. Sonra isntThisAnnoying s (S m) yerine runState t s yazabilirsiniz tS m ile aynıdır.
newtype kullanmanız gerekir, çünkü eşanlamlı yazım örnekleri örnek olamaz.