was Sie beabsichtigen, ist die Monade Maybe
, verwenden, die automatisch die Nothing
nach unten geht, so dass Sie das nicht manuell handhaben müssen.
so könnten Sie den Typ (ReaderT r Maybe)(a)
anstelle von (Reader r)(Maybe a)
verwenden.
aber ich denke, dass Sie dies schließlich zu r -> Maybe a
vereinfachen möchten.
wie auch immer, das Sie verwenden Monad Reader r
, die der Versorgung eines Parameters nur eine andere Art ist. weil r->a
ist nur syntaktischer Zucker für (->) r a
und (->) r
ist bereits ein Reader Monad, können Sie stattdessen verwenden: Sie könnten sogar ersetzen ask
mit id
.
Sie wahrscheinlich nicht die alberne ask
Funktion die ganze Zeit verwenden möchten, so können Sie reader
verwenden, um einfach die Funktion zu heben.
evalExpM :: Exp -> Reader (Map.Map String Int) (Maybe Int)
evalExpM (EVar var) = ask >>= (\x -> lift (Map.lookup var x))
evalExpM (EVar var) = reader $ \x -> Map.lookup var x
evalExpM (EVar var) = reader $ Map.lookup var
ist es bequemer Reader
(oder ReaderT
) nur zu verwenden, wenn Sie automatisch möchten die param an inneren Funktionen übergeben.Aber selbst dann können Sie einfach die Monad (->) r
verwenden oder einfach einen Parameter übergeben. Sie erhalten ein besseres Gefühl dafür, wenn Sie immer die Monad (->) r
und id
anstelle von Reader r
und ask
verwenden. für ReaderT
auf der anderen Seite, werden Sie sehen, ihre Notwendigkeit, wenn Sie einen Parameter an die meisten Funktionen übergeben müssen Sie in do
Notation verwenden.
evalExp :: Exp -> Map.Map String Int -> Maybe Int
evalExp (EOp OpSub e1 e2) = ask >>= (\x -> return (Just ((fromJust ({-runReader-} (evalExp e1) x)) - (fromJust ({-runReader-} (evalExp e2) x)))))
evalExp (EOp OpSub e1 e2) = do -- Monad ((->) (Map.Map String Int))
x <- id -- hehe, same as ask
return (Just ((fromJust ({-runReader-} (evalExp e1) x)) - (fromJust ({-runReader-} (evalExp e2) x))))
evalExp (EOp OpSub e1 e2) x = -- directly with param x
(Just ((fromJust ((evalExp e1) x)) - (fromJust ((evalExp e2) x))))
evalExp (EOp OpSub e1 e2) x = do -- Monad (Maybe)
let a = fromJust ((evalExp e1) x)
let b = fromJust ((evalExp e2) x)
Just $ a - b
evalExp (EOp OpSub e1 e2) x = do -- Monad (Maybe)
a <- return $ fromJust ((evalExp e1) x)
b <- return $ fromJust ((evalExp e2) x)
Just $ a - b
-- and without that bug:
evalExp (EOp OpSub e1 e2) x = do -- because return=Just
a <- evalExp e1 x
b <- evalExp e2 x
return $ a - b
evalExp (EOp OpSub e1 e2) = runReaderT $ do -- Monad (ReaderT (Map...) Maybe)
a <- ReaderT $ evalExp e1
b <- ReaderT $ evalExp e2 -- this is a nice example to use ReaderT
return $ a - b
-- this is ugly unless we need that param wrapped quite often:
evalExpM :: Exp -> ReaderT (Map.Map String Int) Maybe Int
evalExpM exp = ReaderT $ evalExp exp
Statt 'Nur tun (fromJust foo + fromJust bar)', versuchen '(+) <$> foo <*> bar'. Wenn Sie hier das applicative verwenden, vermeiden Sie die unsichere Verwendung von 'fromJust', die die Ausnahme auslöst, die Sie sehen, wenn sie auf ein' Nothing' stößt. Wobei '(+) <$> foo <*> bar' korrekt zu 'Nothing' ausgewertet wird, wenn entweder foo oder bar' Nothing' ist. – hao
Danke, Gibt es einen Weg ohne Applicative? Applicative scheint sehr hart zu sein –
Ich stimme zu 'Applicative' mag auf den ersten Blick ein bisschen kompliziert erscheinen - aber geben Sie es eine Woche der realen Nutzung und Sie finden es wahrscheinlich sehr angenehm (und es ist definitiv wert, zu lernen). – epsilonhalbe