2013-02-26 3 views
3

Я применяю свои (ограниченные) знания Haskell к веб-фреймворку Snap и вижу, что я могу построить. Я пытаюсь получить (возможно, несуществующий) параметр и проанализировать его в int. Очевидно, «Возможно» - это то, чего я хочу.Snap framework - повторяющийся, возможно, уборка

В коде ниже AppHandler определяется как Handler App App (монада с двумя уровнями состояния, я думаю, хотя я ничего не могу найти в учебнике). B8 является ByteString.Char8 и readInt возвращается Maybe(Int,ByteString)

ниже код работает, но предположительно должен быть способ цепочке, может быть, созовет (через MaybeT предположительно, так как я нахожусь в монады уже). Цепочка имеет особое значение, потому что следующим шагом будет выборка из базы данных на основе проанализированного идентификатора, поэтому, конечно, это вернет «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 и param будет либо ByteString, либо мы получим Nothing, а остальная часть блока do-short будет короткозамкнута * , Аналогично на линии 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 и применяет fst к Maybe (Int,ByteString), чтобы мы могли получить Maybe Int.


* Если я правильно понимаю, каждая последующая строка должна быть посещены, а просто возвращает Nothing, так на самом деле не ярлык гото-стиль. Редактировать 2: см. Комментарий kosmikus ниже - лень + право-вложение означает, что нам не нужно оценивать каждую строку.

ответ

7

Вы можете просто использовать локально Maybe монады здесь:

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 
+0

Thanks kosmikus - Кажется, я понял. Аннотированный мой вопрос. –

+0

@RichardHuxton AFAICS, все ваши комментарии в аннотациях полностью верны. – kosmikus

+0

@ RichardHuxton О, за исключением этой сноски о последующих строках, которые необходимо посетить. Дезаурация по умолчанию do-блока по умолчанию состоит в правильной вложенной последовательности монадических привязок '... >> = (\ x -> ... >> = (\ y -> ... >> = ...)) '. Оператор bind для 'Maybe' возвращает' Nothing', как только первый аргумент оценивается как 'Nothing', поэтому нет необходимости посещать или оценивать что-либо из остальных утверждений. – kosmikus

Смежные вопросы