I have a question regarding use of Exceptions with a transformer stack. I am a trying to develop some networking software, specifically implement the GTP control protocol on S5 interface. I am finding it difficult to get Exceptions work the transformer stack.
import Control.Monad (unless)
import Control.Exception
....
import Control.Monad.Trans.State.Strict
import Control.Monad.Trans.Except
...
data GtpcModSt = GtpcModSt { sock :: Socket
, rcvdBytes :: BS.ByteString
, s5cTeidKey :: Word32
---- ....
} --deriving (Show)
type EvalGtpC a = (StateT GtpcModSt (ExceptT GtpcExceptions IO )) a
-- deriving (Functor, Applicative, Monad)
gtpcProcess = loop
where loop = do
rcvAndProcessGtpc `catch` (\e -> do
print "Exception handler"
print (e :: SomeException))
loop
rcvAndProcessGtpc :: EvalGtpC ()
rcvAndProcessGtpc = do
sock <- gets sock
(msg, addr) <- liftIO $ recvFrom sock 1000
modify (\x -> x {rcvdBytes = msg, sndrAddr = addr})
processMsg
processMsg :: EvalGtpC ()
processMsg = do
-- validateSrc
-----
--....
msg <- gets gtpMsg
processGtpc $ msgType msg
-- createSessionRequest
processGtpc :: Word8 -> EvalGtpC ()
processGtpc 32 = do
myState@GtpcModSt {..} <- get
.....
sessParams <- return $ foldl ieInfo (SessionParams { imsi = Nothing
, mei = Nothing
, msisdn = Nothing
, senderFteidKey = Nothing
, senderIpV4Addr = Nothing
, senderIpV6Addr = Nothing
, pgwFteidKey = Nothing
, pgwIpV4Addr = Nothing
, pgwIpV6Addr = Nothing
, apn = Nothing
, paaPdnType = Nothing
, pco = Nothing
, bearerContext = []
, unDecodedIe = []
, unSupportedIe = []
}) $ msgIeList gtpMsg
ueApn <-return $ fromMaybe (throwE BadIe) (apn sessParams)
apnCfg <- return $ fromMaybe (throw BadIe) $ Map.lookup ueApn apnProfile
thisSndrFteidKey <-return $ fromMaybe (throw BadIe) (senderFteidKey sessParams)
I think that I should use throwE
/catchE
from Control.Monad.Trans.Except
. However, throwE
does not even compile when used with my transformer monad, as shown here:
apnCfg <- return $ fromMaybe (throw UnknownApn) $ Map.lookup ueApn apnProfile
Using throw
from Control.Exception
gets past the compilation stage but I am not sure it will work.
Should I not be using Exception in a transformer monad that has IO
as its base?
答案 0 :(得分:1)
我认为我应该使用
throwE
中的catchE
/Control.Monad.Trans.Except
。但是,throwE
在与变换器monad一起使用时甚至无法编译,如下所示:apnCfg <- return $ fromMaybe (throw UnknownApn) $ Map.lookup ueApn apnProfile
使用
throw
中的Control.Exception
已经过了编译阶段,但我不确定它是否可行。
这可以通过遵循类型来解决。在你的do-block中,我们有:
-- I won't use the synonym here, for the sake of explicitness:
return :: a -> StateT GtpcModSt (ExceptT GtpcExceptions IO) a
throwE
的类型是:
throwE :: Monad m => e -> ExceptT e m a
就是这样,你想要的是:
apnCfg <- maybe (lift $ throwE UnknownApn) return $ Map.lookup ueApn apnProfile
首先,如果您没有投掷,则只需要return
(maybe
比fromMaybe
表达更方便)。其次,throwE
生成ExceptT
计算,您需要lift
到外层StateT
层。您可以直接使用 mtl 而不是转换器来隐式lift
。为此,请从...中更改导入
import Control.Monad.Trans.State.Strict
import Control.Monad.Trans.Except
......来:
import Control.Monad.State.Strict
import Control.Monad.Except
然后您可以简单地编写(使用MonadError
中的throwError
方法):
apnCfg <- maybe (throwError UnknownApn) return $ Map.lookup ueApn apnProfile