Haskell Snap Framework - 类型不匹配ByteString / Maybe ByteString

时间:2013-07-29 18:25:41

标签: haskell haskell-snap-framework

我对Haskell和Snap相当陌生,我正在通过我自己的项目使用snap进行小型网络论坛。我遇到的问题是了解冲突以及如何解决以下代码。

handleCategoryAdd :: H ()
handleCategoryAdd = method POST (withLoggedInUser go)
  where
    go user = do
      bs <- getParam "categoryName"
      cN <- B.unpack $ Just bs
      cD <- getParam "categoryDesc"
      cT <- getCurrentTime
      return (Db.saveCategory (Db.Category 1 cN cT "1" ))
      redirect "/"

给我一​​个类型不匹配错误如下:

src\Site.hs:118:22:
    Couldn't match expected type `ByteString'
                with actual type `Maybe ByteString'
    In the first argument of `unpack', namely `bs'
    In a stmt of a 'do' block: cN <- unpack bs
    In the expression:
      do { bs <- getParam "categoryName";
           cN <- unpack bs;
           cD <- getParam "categoryDesc";
           cT <- getCurrentTime;
           .... }

任何清除混淆的建议都会非常感激,我一直在寻找一些解开may的方法,只是检索字节串但是没有成功。

非常感谢!

2 个答案:

答案 0 :(得分:3)

JustMaybe a类型的构造函数。 getParam,我非常确定,返回Snap Maybe Bytestring,因此bs的类型为Maybe Bytestring。当你说Just bs时,你会Maybe (Maybe Bytestring),这显然是你不想要的。您正在寻找fromJust :: Maybe a -> a,但此功能很危险,因为您还没有检查getParam是否成功,并且html页面上有一个输入,并带有该名称。

您应该做的是用例或>>=

这样的东西
bs <- getParam "categoryName"
case bs of
   Nothing -> writeBS "failed"
   Just b  -> do
      let unpacked = B.unpack b
      -- ... Do more stuff

修改

这取决于你想要做什么。绑定可能很有用,因此可以liftMlifM2liftM3等。

在您的情况下,您可能需要liftM2。我不知道你的类型是什么,但我会给出一个非常简单的例子。除了那些2 Bytestrings你可以做这样的事情。

bs1 <- getParam "one"
bs2 <- getParam "two"

case (liftM2 append bs1 bs2) of
   Nothing -> writeBS "Failed"
   Just b  -> writeBS b

答案 1 :(得分:1)

Maybe a类型中提取值的一种好方法是使用fromMaybe模块中的Data.Maybe函数。如果您在Nothing中有Maybe值的情况下使用默认值,则非常有用。

我将在IO monad而不是一些Snap monad中提供一个示例,以避免拉入Snap库以使演示代码工作,但它应该工作相同(除了类型签名更改),只要处理程序与getParam操作位于同一个monad中。

{-# LANGUAGE OverloadedStrings #-}
import           Data.Maybe
import           Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B

getParam1, getParam2 :: IO (Maybe ByteString)
getParam1 = return $ Just "Hello"
getParam2 = return $ Nothing

main :: IO ()
main = do
   str1 <- getParam1 >>= return . fromMaybe "No value"
   str2 <- getParam2 >>= return . fromMaybe "No value"

   B.putStrLn str1
   B.putStrLn str2

由于getParam1getParam2IO (Maybe ByteString),我们知道我们需要使用monadic动作来获取内部的Maybe ByteString值。

通过查看>>=的{​​{1}}类型签名,我们可以将m a -> (a -> m b) -> m b类型设置为a,并将Maybe ByteString类型设置为{ {1}},这意味着我们希望将绑定应用于这些特定类型:

b

考虑到这一点,我们可以查看IO ByteString的类型:

-- (Type of getParam1 >>= Type of our function to supply)    -> Desired type 
IO (Maybe ByteString) -> (Maybe ByteString -> IO ByteString) -> IO ByteString

我们可以使用默认的ByteString部分应用fromMaybe并获取:

fromMaybe

现在我们使用fromMaybe :: a -> Maybe a -> a 撰写该功能,将fromMaybe "No value" :: Maybe ByteString -> ByteString 放回return

ByteString

这是我们在IO的结果上使用return . fromMaybe "No value" :: Maybe ByteString -> IO ByteString 所需的类型。

由于我们位于>>= monad的getParam1块中,因此我们可以使用do绑定箭头语法提取IO以供进一步使用:

ByteString

此时,<-中的str1 <- getParam1 >>= return . fromMaybe "No value" ByteString可以在str1区块中使用。

希望您觉得这个解释很有帮助!