2010-10-31 3 views
7

Ich muss eine Statusmonade schreiben, die auch die Fehlerbehandlung unterstützen kann. Ich dachte an die Verwendung der Entweder-Monade für diesen Zweck, weil es auch Details darüber geben kann, was den Fehler verursacht hat. Ich habe eine Definition für eine staatliche Monade gefunden, die die Maybe-Monade verwendet, aber ich bin nicht in der Lage, sie so zu modifizieren, dass sie entweder statt Maybe verwendet. Hier ist der Code:Wie kann ich eine Zustands-Monade schreiben, die Fehlerbehandlung auch tut?

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} 

Antwort

6

Es gibt zwei mögliche Lösungen. Derjenige, der am nächsten zu dem Code Sie oben vorgesehen ist:

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 
    } 

Die andere Form bewegt den Fehler bei der Verarbeitung Zustand Handhabung:

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

Ich sehe den Unterschied zwischen dem ersten Codeblock und dem zweiten nicht. Haben Sie versehentlich den gleichen Code zweimal eingegeben oder, wenn nicht, können Sie den Unterschied klären? – seh

+0

@seh, guter Fang, es ist aktualisiert –

+3

Beachten Sie auch, dass diese beiden operativ ein wenig anders sind. Die zweite Version ermöglicht fortsetzbare Fehler, während die erste Version beim ersten Fehler endet. Wenn Sie die Protokollierung modellieren, sollten Sie beachten, dass die erste Version auch den Anmeldefehler "verliert". –

4

Sie benötigen einen Monade Transformator. Monad Transformer-Bibliotheken wie mtl ermöglichen es Ihnen, verschiedene Monaden zu einer neuen Version zu erstellen. Mit mtl könnten Sie

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

definieren, die es Ihnen ermöglicht sowohl den Zugriff auf Zustand und Fehler in Ihrem StateMonad Handhabung.

2

Sie können immer einen ErrorT-Monade-Transformer mit einer State-Monade verwenden (oder umgekehrt). Werfen Sie einen Blick auf die Transformatoren von all about monads.

HTH,

+1

Aktualisierter Link: http://www.haskell.org/haskellwiki/All_About_Monads – sinelaw

9

Betrachten ExceptT von Control.Monad.Trans.Except mit (statt Entweder verwenden).

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 

Wenn Sie sich nicht wohl mit Monaden und Monade Transformatoren, dann würde ich das tun erste! Sie sind eine große Hilfe und Programmierer Produktivität Leistung zu gewinnen.