3

我正在将我(有限的)Haskell 知识应用到 Snap Web 框架中,看看我能构建什么。我正在尝试获取一个(可能不存在的)参数并将其解析为一个 int。显然“也许”是我想要的。

在下面的代码中AppHandler定义为Handler App App(我认为具有两个状态级别的 monad,尽管我现在在教程中找不到任何东西)。B8ByteString.Char8readInt返回_Maybe(Int,ByteString)

下面的代码有效,但大概应该有一种方法将可能的调用链接在一起(大概是通过MaybeT,因为我已经在 Monad 中了)。链接特别有意义,因为下一步将根据解析的 id 从数据库中获取一行,所以当然这也会返回一个“Maybe a”。显然,这是一种非常普遍的模式。

-- Given a parameter name, return the Int it points to
-- or Nothing if there is some problem
maybeIntParam :: ByteString -> AppHandler (Maybe Int)
maybeIntParam pname = do
    raw_param <- getParam pname
    let mb_i_b = maybe (Nothing) B8.readInt raw_param
    case mb_i_b of
        Nothing    -> return Nothing
        Just (p,_) -> return $ Just p

我尝试应用 runMaybeT 但坦率地说,我没有真正了解需要更改的类型,我正在随机更改以希望错误消失。它没有,尽管它改变并从一行到另一行移动。

我将此视为进步,因为我现在完全迷失在一个比我开始探索 Haskell 时更高的水平......


编辑:遍历kosmikus的答案,希望我已经理解了...

1 maybeIntParam :: ByteString -> AppHandler (Maybe Int)
2 maybeIntParam pname = do
3     raw_param <- getParam pname
4     return $ do
5       param  <- raw_param
6       (p, _) <- B8.readInt param
7       return p

我想我正试图朝着这个方向努力,但一直试图getParam在与其他步骤相同的块内强行。

在第 3 行,对 getParam 的调用发生在 AppHandler 中。我们有 raw_param 这是一个Maybe ByteString. 在第 5 行,我们在一个嵌套的 do 中,所以绑定(?)发生在 Maybe monadparam中,要么是 aByteString要么我们得到Nothing,其余的 do 块将短路*。同样在第 6 行,p 要么是 Int,要么我们短路。

一切顺利,第 6 行p包含一个 Int (比如 42),第 7 行将返回Just 42. 回到第 4 行,变成AppHandler (Just 42). 现在不需要关心 AppHandler 是什么 - 类型都很高兴。

这里有一些变体也可以进行类型检查,并且可能证明对那些试图思考这一点的人有用。

maybeIntParam1 :: ByteString -> AppHandler (Maybe Int)
maybeIntParam1 pname = do
    raw_param <- getParam pname
    let mb_int_param = do
        param  <- raw_param
        (p, _) <- B8.readInt param
        return p
    return mb_int_param

maybeIntParam2 :: ByteString -> AppHandler (Maybe Int)
maybeIntParam2 pname = do
    return $ return 27

maybeIntParam3 :: ByteString -> AppHandler (Maybe Int)
maybeIntParam3 pname = do
    return (Just 27)

在这种情况下,非执行变体实际上看起来更简单。唯一需要考虑的是<$>,如果我没看错的话,它是公正fmap的,并且适用于fstMaybe (Int,ByteString)所以我们可以得到Maybe Int


*如果我理解正确,则必须访问后续每一行,但只返回 Nothing,因此实际上不是 goto 样式的快捷方式。 Edit2:请参阅下面的 kosmikus 评论 - 懒惰 + 右嵌套意味着我们不需要评估每一行。

4

1 回答 1

7

您可以在Maybe这里本地使用 monad:

maybeIntParam :: ByteString -> AppHandler (Maybe Int)
maybeIntParam pname = do
    raw_param <- getParam pname
    return $ do
      param  <- raw_param
      (p, _) <- B8.readInt param
      return p

或者,如果您愿意,可以将Maybe-computations 编写为单行:

maybeIntParam :: ByteString -> AppHandler (Maybe Int)
maybeIntParam pname = do
    raw_param <- getParam pname
    return $ fst <$> (raw_param >>= B8.readInt)

涉及的一些类型:

raw_param                          :: Maybe ByteString
B8.readInt                         :: ByteString -> Maybe (Int, ByteString)
raw_param >>= B8.readInt           :: Maybe (Int, ByteString)
fst                                :: (Int, ByteString) -> Int
fst <$> (raw_param >>= B8.readInt) :: Maybe Int
于 2013-02-26T15:33:47.730 回答