, что вы собираетесь это использовать монаду Maybe
, которая автоматически проходит Nothing
вниз, так что вам не нужно, чтобы справиться с этим вручную.
поэтому, вы можете использовать тип (ReaderT r Maybe)(a)
вместо (Reader r)(Maybe a)
.
, но я думаю, вы в конечном итоге хотите упростить это до r -> Maybe a
.
в любом случае, вы используете Монадой Reader r
, который только причудливый способ подачи параметра. потому что r->a
является только синтаксическим сахаром для (->) r a
и (->) r
уже является читателем Monad, вы можете использовать его вместо этого: вы могли бы заменить ask
на id
.
Вы, вероятно, не хотите использовать глупую функцию ask
все время, поэтому вы можете использовать reader
, чтобы просто снять функцию.
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
удобнее использовать Reader
(или ReaderT
) только тогда, когда вы хотите, чтобы автоматически передавать из параметров для внутренних функций.но даже тогда вы можете просто использовать Monad (->) r
или просто передать параметр. вы получите лучшее чувство для этого, если вы всегда используете Monad (->) r
и id
вместо Reader r
и ask
. для ReaderT
, с другой стороны, вы увидите его необходимость, когда вам нужно передать один параметр для большинства функций, которые вы используете в нотации .
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
Вместо того чтобы делать 'Just (fromJust Foo + fromJust бар)', попробуйте '(+) <$> Foo <*> bar'. Использование данного приложения позволяет избежать небезопасного использования 'fromJust', который генерирует исключение, которое вы видите, когда оно встречается с« Nothing ». В то время как '(+) <$> foo <*> bar' правильно оценивает 'Nothing', когда foo или bar является' Nothing'. – hao
Спасибо, существует ли способ без аппликативного? Аппликация кажется очень сложной. –
Я согласен. «Аппликативный» может показаться немного сложным вначале - но дайте ему неделю реального использования, и вы, вероятно, найдете его вполне приемлемым (и это определенно стоит изучить). – epsilonhalbe