在最后两个星期才开始写这学期的项目设计,AngularJS也是现学现卖,虽然时间有点赶,我自己还是比较满意的。因为是个挺RESTful的东西,服务器端是用scotty写的,最初有很多嵌套的if…then…else处理错误:
handleSend :: AppState -> ActionM ()
handleSend AppState{..} = do
logined <- isLogined tokenStore
when logined $ do
msend <- jsonDataMaybe
resp <- case msend of
Nothing -> return $ Fail 0 "请输入完整信息"
Just req@SendMsg{..} -> do
isfriend <- isFriend database from to
if (not isfriend)
then return $ Fail 1 "发送失败"
else do
tmsg <- liftIO $ tagTime req
liftIO $ void $ forkIO $ do
sendMessage messageQueue (TM tmsg)
insertMessage database (TM tmsg)
return $ Success tmsg
jsonResp resp
简直无法直视啊。其实我需要的只是early return。想过用monad transformer,但是只能实现类似ActionT a (ErrorT b IO)
的monad,ErrorT
在ActionT
之下,在ErrorT
里的短路是不会影响到ActionT
的。后来我才发现ActionT
其实就是有ErrorT
的,可以直接用。
handleSend :: AppState -> ActionT ErrorResult IO ()
handleSend AppState{..} = handleError $ do
isLogined tokenStore `expectTrue` Unauth
req@SendMsg{..} <- jsonData <?> Fail 0 "请输入完整信息"
isFriend database from to `expectTrue` Fail 1 "发送失败"
tmsg <- liftIO $ tagTime req
liftIO $ void $ forkIO $ do
sendMessage messageQueue (TM tmsg)
insertMessage database (TM tmsg)
json $ Success tmsg
其中用到一些自己定义的函数,用来检查结果和加上自定义的错误类型(ErrorResult ):
act <?> err = act `rescue` (const $ raise err)
expectTrue act err = do
true <- act
when (not true) (raise err)
expectRight act err = act >>= either (const $ raise err) return
expectJust act err = act >>= maybe (raise err) return
handleError act = act `rescue` json
还可以defaultHandler替换全局的异常处理函数。另一个问题是raise
和rescue
只能处理ErrorT
里的错误,不能处理异常(Control.Exception
),那些异常还是要自己处理。
正文:
好像是两天前,带着报告和笔记本准备去答辩,徘徊了半个钟才找到老师。
老师: 答辩还是交报告?
我:交报告
啊,终于不用被答辩啦,虽然感觉不太对劲。