Имбирь - твой спиритический овощ. Войти !bnw Сегодня Клубы
Привет, TbI — HRWKA! 1235.3 пользователей не могут ошибаться!
?6906
прекрасное6424
говно5886
говнорашка5512
хуита4695
anime3056
linux2645
music2620
bnw2588
рашка2559
log2337
ололо2113
pic1811
дунч1734
сталирасты1488
украина1437
быдло1434
bnw_ppl1369
дыбр1237
гімно1158

Драйвер редиса возвращает Redis (Either Reply a). При операции HGET возвращает, соответственно, Redis (Either Reply (Maybe ByteString)), типа значения по ключу может и не быть. Программист для упрощения пишет сначала специальную функцию redis', которая заворачивает ответ редиса в EitherT-based монаду, чтоб соединять подобные вычисления и возвращать первую неудачу:

newtype Redis' a = Redis' (EitherT Redis.Reply Redis.Redis a) deriving (MonadIO)
instance Monad Redis' where
    return = Redis' . EitherT . return . Right
    (Redis' m) >>= f = Redis' $ m >>= \rv -> unwrapRedis' $ f rv
redis' = Redis' . EitherT

Таким образом, теперь, если вы получаете ответ Redis (Either Reply a), вы его преобразуете в

Redis' (EitherT Reply Redis a)

и можете соединять подобные вычисления в do-блоке типа:

do
    res <- redis' $ Redis.hget foo bar
    res2 <- redis' $ Redis.hget baz zab

и вычисление остановится на первом возврате ошибки.

Далее. Программисту необходимо по кучке значений сделать HGET и вернуть это как-то внутри кортежа, поскольку мы внутри новой монады Redis' -- завернуть результат в неё. В случае, если значения хоть по одному ключу не существует, хочется вернуть Nothing для всех. Потому создаётся новая монада:

newtype HashFields a = HashFields (MaybeT Redis' a)
    deriving (Functor, Monad)
instance Applicative HashFields where
    pure = return
    (<*>) = ap

описывающая вычисления типа Redis', которые могут вернуть неудачу. Пишется новая функция

hashField = HashFields . MaybeT . redis'

способная завернуть результат неудачи в новую монаду, которая умеет останавливаться на первой неудаче. Также пишется специальная функция для HGET:

getField :: ByteString -- ^ Key
         -> ByteString -- ^ Hash field name
         -> HashFields String
getField key field = fmap toString $ hashField $ Redis.hget key field

Также напишем функцию, которая "запустит" наше вычисление:

getRedisFields :: forall a. HashFields a -> Redis' (Maybe a)
getRedisFields (HashFields f) = runMaybeT f

И теперь лёгким движением руки мы можем сделать что-то вроде:

getRedisFields ((,,,,,) <$>
    getField k "foo" <*>
    getField k "bar" <*>
    getField k "baz" <*>
    getField k "zab" <*>
    getField k "rab" <*>
    getField k "oof")

Вопрос: вам не кажется это "слишком"? Я пока еще не настолько просто манипулирую типами в голове, чтоб ощутить всю ситуацию, хорошо хоть в целом могу медленно прости по шагам по коду, но есть ощущение, что что-то здесь не так.

#DEENSA (6+1) / @kb / 3812 дней назад
ipv6 ready BnW для ведрофона BnW на Реформале Викивач Котятки

Цоперайт © 2010-2016 @stiletto.