正在清理快照路由处理程序(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)

这里有几件事:

  1. CCD_ 1具有签名CCD_。我意识到我必须做点什么才能把peptideSequenceMaybe ByteString变成ByteString,所以这似乎是必要的(而且做起来并不痛苦),但是
  2. Maybe ByteString转换为Float似乎有点可笑。有更好的方法来处理这个问题吗?还是这只是需要向下推到calculationResults函数中,并让它处理转换

我想我正试图从"在泡沫中学习haskell"扩展到包括它实际是如何完成的,而不是对编译器进行猛烈抨击,直到它最终放弃并说"好吧,我让它通过"。

提前感谢您的意见!

一些事情。

fromJust相当邪恶。它相当于纯代码世界中的calculationResults0。您正在从Maybe monad中提取一个值,该值没有模式匹配。

fromJust :: Maybe a -> a
unsafePerformIO :: IO a -> a
> fromJust Nothing
*** Exception: Maybe.fromJust: Nothing

现在,您的HTML很可能不会被恶意操纵,因此这些参数将返回Nothing。但是,如果真的发生了这种情况,您应该使用Snap的内置故障机制,它是Monad类中fail的Snaps实现。它比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 monod中操作,那你就太倒霉了。Snap已覆盖fail的默认实现。

来自RWH:

小心失败许多Monad实例不会覆盖默认值我们在这里展示的fail的实现,所以在那些monad中,fail使用错误。调用错误通常是非常不可取的,因为引发调用方无法捕获或不会捕获的异常预料

即使你现在知道你在一个已经失败做一些更明智的事情,我们仍然建议避免太容易在以后重构时给自己带来问题代码,并忘记以前安全使用fail可能是危险的在新的背景下。

尽管如此,我仍然使用它,因为它在这种情况下是有意义的(除非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"是位于:: Float -> ByteString1中的文件"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

最新更新