Reputation:
I am writing interpreter in Haskell and I have map: name_of_function -> defintion of function.
Map String Defun
My interpreter monad:
type InterpreterMonad = StateT (EnvFun, (Stack EnvEval)) (ErrorT String IO ) ()
And as you can see "last" monad is ErroT
.
Now, when I would like handle calling functions:
handleFCall :: Stmt -> InterpreterMonad
handleFCall (VarName name) args = get >>= \(envFun, contextStack) -> case (Map.lookup (VarName name) envFun) of
Nothing -> throwError "Err"
(Just x) -> DoSthOther
And as you can see I have to use case
. However I am using >>=
so I would like to avoid case of
here. But, Map.lookup
return Nothing
on fail and I would like to add my error message.
I have no experience in Haskell so I don't know how to deal with it . Morever, every criticism to my code is welcome.
Cheers.
Upvotes: 2
Views: 1532
Reputation: 30227
The errors
package has the following operations in Control.Error.Util
(and reexported from Control.Error
):
-- You can turn `Maybe` into `Either` by supplying a constant to use
-- for the `Left` case.
note :: a -> Maybe b -> Either a b
-- Ditto for `MaybeT` and `ExceptT`
noteT :: Monad m => a -> MaybeT m b -> ExceptT a m b
-- And there are useful shortcuts for other combinations
failWith :: Applicative m => e -> Maybe a -> ExceptT e m a
failWith
in particular looks like it would fit quite nicely here, something like this expression would do the trick.
failWith "Err" (Map.lookup (VarName name) envFun)
Note that the ErrorT
transformer that you're using in your example has been deprecated in favor of ExceptT
(as the signatures above are using), so you'd have to change your code accordingly to use the errors
package. On the other hand these functions are simple enough that you can just bake your own if you so prefer.
Upvotes: 2
Reputation: 54058
There's nothing wrong with using a case statement, although reformatted with do notation your function would look more like
handleFCall (VarName name) args = do
(envFun, contextStack) <- get
case Map.lookup (VarName name) envFun of
Nothing -> throwError "Err"
Just x -> doSthOther x
Which would be more familiar to other Haskell programmers. However, if you really want to avoid using a case, just use the maybe
function:
handleFCall (VarName name) args = do
(envFun, contextStack) <- get
maybe (throwError "Err") doSthOther $ Map.lookup (VarName name) envFun
Or with >>=
handleFCall (VarName name) args
= get >>=
(\(envFun, contextStack) ->
maybe (throwError "Err") doSthOther
$ Map.lookup (VarName name) envFun
)
But personally I find the case statement more readable.
Upvotes: 4