2013-05-06 6 views
7

Ich habe folgende Datentyp in Haskell:Pattern Match gegen Wert in Monade

data Flow a = Continue a | Return Value 
newtype FlowT m a = FlowT {runFlowT :: m (Flow a)} 
type IStateM a = FlowT (StateT IState IO) a 

wo IState ist eine Art Rekord einige Listen usw. Monad und MonadTrans Instanzen für Flowt enthalten, werden wie folgt definieren:

instance (Monad m) => Monad (FlowT m) where 
x >>= f = FlowT $ do 
        unwrapped <- runFlowT x 
        case unwrapped of 
         Continue v -> runFlowT (f v) 
         Return r -> return $ Return r 
return x = FlowT $ return (Continue x) 


instance MonadTrans FlowT where 
    lift m = FlowT (Continue `liftM` m) 

instance (MonadIO m) => MonadIO (FlowT m) where 
    liftIO m = lift (liftIO m) 

instance (MonadState s m) => MonadState s (FlowT m) where 
    put k = lift (put k) 
    get = lift get 

Meine Absicht war, dass in der Spielzeugsprache, für die ich einen Interpreter entwickle, Sie jederzeit von der Funktion zurückkehren können, indem Sie mit einem Ausdruck zurückkehren. Jetzt, wenn ich Code schreibe, um den Aufruf der Funktion zu interpretieren, muss ich den Flow-Wert extrahieren, der hinter den Kulissen in dieser Monade übergeben wird. Ich kann keine Übereinstimmung mit IState() finden, weil es IO enthält. Die Funktion, die ich brauche, sollte auf ähnliche Weise arbeiten, wie State funktioniert - ich rufe es an und kann prüfen, ob ein Wert zurückgegeben wird, und wenn ja, bekomme ich es, wenn nein, sagen wir, dass ein spezieller Wert vom Typ Value zurückgegeben wird oder so . Wie macht man das?

Antwort

8

Um Mustererkennung auf den Wert, Sie das Ergebnis innerhalb des gegebenen Monade binden muss, die genau die gleiche Art und Weise Sie in Ihrem Monad Instanz tat

interpret :: FlowT m a -> m a 
interpret flow = do 
    value <- runFlowT flow 
    case value of 
     Continue v -> ... 
     Return r -> ... 

Als Seite beachten, haben Sie eine besondere neu erfunden Fall von free monad transformers, und Sie können die offizielle Implementierung von ihnen in the free package finden.

Insbesondere Ihr FlowT Typ ist identisch mit:

import Control.Monad.Trans.Free -- from the 'free' package 
import Data.Functor.Constant  -- from the 'transformers' package 

type FlowT = FreeT (Constant Value) 

Dies einem isomorph Typen mit dem exakt gleichen Verhalten gibt, und die gleichen Monad und MonadTrans Instanzen.

Aber zurück zu Ihrer spezifischen Frage: Nein, es gibt keine Möglichkeit, die Übereinstimmung auf den Wert zu mattern, ohne das Ergebnis zuerst in der Basismonade zu binden.

+0

Ich weiß nicht, wie das möglich ist, aber ich bin mir ziemlich sicher, dass ich das schon einmal versucht habe und es hat nicht funktioniert. Aber nachdem ich deinen Beitrag gelesen und meinen Code umgeschrieben hatte, habe ich ihn auf magische Weise zum Laufen gebracht. Ich habe keine Ahnung, was los war :) Von Control.Monad.Trans.Free wusste ich nichts. Danke für die Hilfe –

+0

Es passiert mir auch, mach dir keine Sorgen. :) –