[英]Cleaning up Snap Route Handler (Haskell)
我正在使用針對haskell的snap框架創建一個站點,而且我仍然是haskell(和snap)的新手。 我希望找到一種“更好”的方式來編寫這個路由處理程序。
possibleMatches :: Snap ()
possibleMatches = do
peptideSequence <- getParam "peptide_sequence"
foundWeight <- getParam "weight"
let results = calculationResults (read . C8.unpack $ (fromJust foundWeight)) (fromJust peptideSequence)
maybe (writeBS "must specify params in URL")
writeJSON $ Just (results)
這里有幾件事:
calculationResults
有signature :: Float -> ByteString
。 我意識到我必須做一些事情才能將peptideSequence
從Maybe ByteString
變為ByteString
,所以這似乎是必要的(而且不是非常痛苦),但是 Maybe ByteString
轉換為Float
似乎有點荒謬。 有沒有更好的方法來處理這個? 或者這只是需要被推入calculationResults
函數的東西,並讓它處理轉換? 我想我正試圖從“學習泡沫中的哈斯克爾”中擴展到包括它是如何實際完成的,而不是在編譯器上敲擊它直到它最終放棄並說“好我會讓它通過”。
提前感謝您的意見!
一些東西。
fromJust
只是非常邪惡。 這相當於純代碼世界中的unsafePerformIO
。 你正在從一個沒有模式匹配的Maybe
monad中提取一個值。
fromJust :: Maybe a -> a
unsafePerformIO :: IO a -> a
> fromJust Nothing
*** Exception: Maybe.fromJust: Nothing
現在,賠率是你的HTML不會被惡意操縱,以便這些參數將返回Nothing
。 但是,如果確實發生了這種情況,你應該使用Snap的內置故障機制,它是Monad類的Snaps實現fail
。 它比fromJust更安全,並且由模式匹配失敗觸發。 您可以通過getParam上的模式匹配來使用它。 ( Just peptideSequence <- getParam "peptide_sequence"
)
instance Monad Snap where
(>>=) = snapBind
return = snapReturn
fail = snapFail
snapFail實現為
snapFail :: String -> Snap a
snapFail !m = Snap $! return $! PassOnProcessing m
PassOnProcessing
將優雅地處理模式匹配失敗。
更多信息在代碼中:
http://hackage.haskell.org/package/snap-core-0.8.0.1/docs/src/Snap-Internal-Types.html
邊注:
所有monad都有一個默認的fail實現,但如果沒有覆蓋,結果往往是不受歡迎的。 任何不受歡迎的我都意味着它會拋出一個只能在IO monad中捕獲的異常,但是如果你不是在IO monad中運行,那么你運氣不好。 Snap已覆蓋默認的fail實現。
來自RWH:
小心失敗。 許多Monad實例不會覆蓋我們在此處顯示的默認失敗實現,因此在這些monad中,fail使用錯誤。 調用錯誤通常是非常不受歡迎的,因為它會拋出一個異常,即調用者無法捕獲或不期望。
即使你現在知道你在一個失敗的monad中執行更合理的事情,我們仍然建議避免它。 當您重構代碼並忘記以前安全使用失敗在新環境中可能是危險的時候,很容易讓自己成為一個問題。
我仍然使用它,因為它在這種情況下是有意義的(除非Snap作者想要糾正我)
我會得到CalculationResults
的結果返回一個JSON
結果。 我還會在CalculationResults
函數中處理Float
類型轉換,可能會使它更清晰
possibleMatches :: Snap ()
possibleMatches = do
Just peptideSequence <- getParam "peptide_sequence"
Just foundWeight <- getParam "weight"
writeJSON $ calculationResults (read $ C8.unpack foundWeight) peptideSequence
要么
possibleMatches :: Handler App (AuthManager App) ()
possibleMatches = do
(peptideSequence, foundWeight) <- (,) <$> getParam "peptide_sequence" <*> getParam "weight"
writeJSON $ calculationResults (read $ C8.unpack foundWeight) peptideSequence
更新:
要在Snap中進行更強大的錯誤處理,您可以使用以下代碼:
catchError :: HasHeist b => ByteString -> Handler b v () -> Handler b v ()
catchError msg action = action `catch` \(e::SomeException) -> go
where go = do logError msg
modifyResponse $ setResponseCode 500
render "500"
其中“500”是位於snaplets/heist/templates/500.tpl
中的文件"500.tpl"
的名稱要將其應用於您的一個處理程序,您可以執行以下操作:
handleNewUser :: Handler App (AuthManager App) ()
handleNewUser = method GET handleGet <|> method POST handlePost
where
handleGet = currentUser >>= maybe the404 (\_ -> render "profile")
handlePost = catchError "Error during login" $ do
setTimeout 100
Just login <- getParam "login"
if | isValid login -> do user <- registerUser "login" "password"
either (\_ -> render "error") (handleUser login) user
| otherwise -> render "error"
handleUser = -- etc etc
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.