2010-10-31 22 views
7

Hata işlemeyi de destekleyebilen bir durum monad yazmalıyım. Bu amaçla E monad'ı kullanmayı düşünüyordum çünkü hataya neden olan şey hakkında ayrıntılar da sağlayabilir. Ben bir durum monad için Belki monad kullanarak bir tanım buldum, ancak Ben, yerine Belki kullanmak için değiştiremiyorum. İşte kod:Hata işleme de yapan bir durum monadını nasıl yazabilirim?

newtype StateMonad a = StateMonad (State -> Maybe (a, State)) 

instance Monad StateMonad where 
(StateMonad p) >>= k = StateMonad (\s0 -> case p s0 of 
           Just (val, s1) -> let (StateMonad q) = k val in q s1 
           Nothing -> Nothing) 
return a = StateMonad (\s -> Just (a,s)) 

data State = State 
{ log :: String 
, a :: Int} 

cevap

6

iki olası çözümü vardır. Eğer yukarıdaki kodu en yakın olandır:

newtype StateMonad e a = StateMonad (State -> (Either e a, State)) 

instance Monad (StateMonad e) where 
    (StateMonad p) >>= k = 
     StateMonad $ \s0 -> 
      case p s0 of 
       (Right val, s1) -> 
        let (StateMonad q) = k val 
        in q s1 
       (Left e, s1) -> (Left e, s1) 
    return a = StateMonad $ \s -> (Right a, s) 

data State = State 
    { log :: String 
    , a :: Int 
    } 
+0

İlk kod bloğu ile ikinci arasındaki farkı göremiyorum. Yanlışlıkla aynı kodu iki kez dahil ettiniz mi, yoksa değilse, farkı açıklayabilir misiniz? – seh

+0

@seh, iyi yakalama, güncellendi –

+3

Ayrıca, bu ikisinin operasyonel olarak biraz farklı olduğunu unutmayın. İkinci sürüm, devam edilebilir hatalara izin verirken, ilk sürüm ilk hatada sonlanır. Günlüğe kaydetme modelleme yapıyorsanız, ilk sürümün de oturum açma hatası olduğunu "kaybeder". –

4

Bir monad trafo gerekir:

newtype StateMonad e a = StateMonad (State -> Either e (a, State)) 

instance Monad (StateMonad e) where 
    (StateMonad p) >>= k = 
     StateMonad $ \s0 -> 
      case p s0 of 
       Right (val, s1) -> 
        let (StateMonad q) = k val 
        in q s1 
       Left e -> Left e 
    return a = StateMonad $ \s -> Right (a, s) 

data State = State 
    { log :: String 
    , a :: Int 
    } 

diğer form durumu ele dahilinde işleme hatayı taşır. mtl gibi Monad trafo kütüphaneleri yeni bir versiyon oluşturmak için farklı monadlar oluşturmanıza izin verir. mtl kullanarak, size StateMonad içinde işleme durumunu ve hatayı hem erişmenize olanak tanır

type StateMonad e a = StateT State (Either e) a 

tanımlayabiliriz.

2

Her zaman bir StateTMad ile bir ErrorT monad trafosunu kullanabilirsiniz (veya tersi). all about monads'un transformatörleri bölümüne bakın.

HTH,

+1

Güncelleme bağlantısı: http://www.haskell.org/haskellwiki/All_About_Monads – sinelaw

9

(yerine kullanarak ve) Control.Monad.Trans.Except den ExceptT kullanabilirsiniz.

import Control.Monad.State 
import Control.Monad.Trans.Except 
import Control.Monad.Identity 

data MyState = S 

type MyMonadT e m a = StateT MyState (ExceptT e m) a 

runMyMonadT :: (Monad m) => MyMonadT e m a -> MyState -> m (Either e a) 
runMyMonadT m = runExceptT . evalStateT m 

type MyMonad e a = MyMonadT e Identity a 
runMyMonad m = runIdentity . runMyMonadT m 

Eğer monads ve Monad transformatörleri ile rahat değilseniz sonra o ilk yapardı! Onlar büyük bir yardım ve programcı verimlilik performansı kazanır. Ben kimseyi görmedim