2013-07-29 1 views
0

Я довольно новичок в Haskell и Snap, и я работаю через свой собственный проект для небольшого веб-форума, используя оснастку. Проблема, с которой я сталкиваюсь, заключается в понимании конфликта и способах решения для следующего кода.Haskell Snap Framework - Тип несоответствия ByteString/Maybe ByteString

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; 
      .... } 

Любые советы, чтобы прояснить путаницу была бы оценена, я искал какой-нибудь способ разворачивать может быть и просто извлечь bytestring, но не увенчались успехом.

Большое спасибо!

ответ

3

Just является конструктором типа Maybe 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 

EDIT

Это зависит от того, что вы пытаетесь сделать. Привязка может быть полезна и поэтому может быть полезна и поэтому может liftM, lifM2, liftM3 и т. Д.

В вашем случае вам может понадобиться лифтM2. Я не знаю, каковы ваши типы, но я приведу очень простой пример. Сохраните, у вас есть эти 2 Bytestrings, которые вы можете сделать примерно так.

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

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

ура это помогло! – stickybynature

+0

как бы вы использовали >> = в этом случае ?? – stickybynature

1

Хороший способ извлечения значения из Maybe a типа состоит в использовании функции fromMaybe из Data.Maybe модуля. Это полезно, если у вас есть значение по умолчанию для использования в случае значения Nothing в Maybe.

Я приведу пример в монаде IO, а не в монашеской Snap, чтобы не вытягивать библиотеки Snap для работы демонстрационного кода, но он должен работать так же (помимо изменений подписи подписи) как долго поскольку обработчик находится в той же монаде, что и действия getParam.

{-# 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 

С getParam1 и getParam2 являются IO (Maybe ByteString), мы знаем, что мы должны использовать монадическое действие, чтобы получить на значение Maybe ByteString внутри.

Глядя на тип подписи >>=, что m a -> (a -> m b) -> m b, мы можем установить тип a быть Maybe ByteString и типа b быть IO ByteString, что означает, что мы ищем, чтобы применить привязку этих конкретных типов:

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

Имея это в виду, мы можем смотреть на тип fromMaybe:

fromMaybe :: a -> Maybe a -> a 

мы можем частично применить fromMaybe с байтовой строки и по умолчанию получают:

fromMaybe "No value" :: Maybe ByteString -> ByteString 

Теперь мы составляем эту функцию с return поставить ByteString назад в IO:

return . fromMaybe "No value" :: Maybe ByteString -> IO ByteString 

Это тип необходимо использовать >>= на результат getParam1 ,

Поскольку мы находимся в do блоке в IO монады, мы можем извлечь ByteString для дальнейшего использования с помощью синтаксиса в <- связывания стрелки:

str1 <- getParam1 >>= return . fromMaybe "No value" 

На данный момент, у вас есть чистый ByteString в str1 к используйте, как видите, в блоке do.

Надеюсь, вы найдете это объяснение полезным!