Stu*_*son 3 haskell haskell-snap-framework
我正在使用针对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)
Run Code Online (Sandbox Code Playgroud)
这里有几件事:
calculationResults有签名:: 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
Run Code Online (Sandbox Code Playgroud)
现在,赔率是你的HTML不会被恶意操纵,以便这些参数将返回Nothing.但是,如果确实发生了这种情况,你应该使用Snap的内置故障机制,它fail是Monad类的Snaps实现.它比fromJust更安全,并且由模式匹配失败触发.您可以通过getParam上的模式匹配来使用它.(Just peptideSequence <- getParam "peptide_sequence")
instance Monad Snap where
(>>=) = snapBind
return = snapReturn
fail = snapFail
Run Code Online (Sandbox Code Playgroud)
snapFail实现为
snapFail :: String -> Snap a
snapFail !m = Snap $! return $! PassOnProcessing m
Run Code Online (Sandbox Code Playgroud)
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结果的结果.我也会处理函数Float内部的类型转换CalculationResults,可能会使它更清晰
possibleMatches :: Snap ()
possibleMatches = do
Just peptideSequence <- getParam "peptide_sequence"
Just foundWeight <- getParam "weight"
writeJSON $ calculationResults (read $ C8.unpack foundWeight) peptideSequence
Run Code Online (Sandbox Code Playgroud)
要么
possibleMatches :: Handler App (AuthManager App) ()
possibleMatches = do
(peptideSequence, foundWeight) <- (,) <$> getParam "peptide_sequence" <*> getParam "weight"
writeJSON $ calculationResults (read $ C8.unpack foundWeight) peptideSequence
Run Code Online (Sandbox Code Playgroud)
更新:
要在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"
Run Code Online (Sandbox Code Playgroud)
其中"500"是"500.tpl"位于的文件的名称snaplets/heist/templates/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
Run Code Online (Sandbox Code Playgroud)