Я и мой ёбаный кот на фоне ковра. Войти !bnw Сегодня Клубы
Снова меня монады победили :( уже час с ними мучаюсь. Пойду запилю вопросом на StackOverflow.
#FS04UK / @kb / 3459 дней назад

@polecat Та вроде разобрался уже. Вот черновик вопроса: ``` I'm getting a little confused regarding error-handling problem. I have a small REST API done via Scotty Haskell web framework. I have a handler that looks like this: jobStatusUpdatePost :: WebAction () jobStatusUpdatePost = do -- validate input data etc. scottyEither $ setJobState s jid newDesc -- render response The main part here is this piece: `scottyEither $ setJobState s jid newDesc`. What's happening is that I have a library function responsible for updating a job state: setJobState :: IO (Either Text ()) I'm fine with it, it's independant of Scotty framework, it's clear what it does and what it returns. But I'm bothered with the fact that I have to put that "scottyEither" that does error-handling inside my scotty action: scottyEither :: (Monad m, ScottyError e) => ActionT e m (Either e a) -> ActionT e m a scottyEither v = v >>= go where go (Left e) = raise e go (Right a) = return a So I wondered, how would I write such a function `setJobState` that: 1. wouldn't be dependent upon scotty web framework's details (not be scotty-specific) 2. would raise exception itself 3. be integrated with ActionT monad (which is why I can't just use `Control.Exception.throw`, sometimes I might want to actually catch it!) ``` Короче оказалось, что в Scotty есть вот этот код: ``` instance (ScottyError e, Monad m) => MonadError (ActionError e) (ActionT e m) where throwError = ActionT . throwError catchError (ActionT m) f = ActionT (catchError m (runAM . f)) ``` то есть можно сделать, например, вот так: ``` setJobState :: (MonadIO m) => JobStateStorage -> JobId -> JobState -> m () setJobState s jid state = do _ <- runRedisThrowing (s ^. redisConn) $ do R.set (getJobStateKey jid) (toStrictByteString (J.encode state)) return () runRedisThrowing :: MonadIO m => R.Connection -> R.Redis (Either R.Reply b) -> m b runRedisThrowing conn act = do r <- liftIO $ R.runRedis conn act either (throw . RedisError) return r ``` И ловить вот так: ``` _ <- catchError (setJobState s jid newDesc) (\err -> do liftIO $ print (showError err)) ``` Косо, криво, через жопу, но хоть что-то. Собственно, чего хотелось бы -- это чтоб через exceptions можно было сделать catch и получить мой Exception, но я так понял, в Scotty плохо сделали и так не получится.
#FS04UK/PPM / @kb --> #FS04UK/A64 / 3459 дней назад
@kb Упрощение: ``` scottyEither v = v >>= either raise return ```
#FS04UK/0C8 / @kb --> #FS04UK/PPM / 3459 дней назад
@polecat Ну вот я тоже не очень их люблю, больше люблю все фигачить в EitherT/ExceptT, но как-то это в подобных случаях, все же, неудобно получается.
#FS04UK/VL0 / @kb --> #FS04UK/8K8 / 3459 дней назад
@kb EitherT == говноедство
#FS04UK/D7L / @pxqr --> #FS04UK/VL0 / 3459 дней назад
@pxqr Но почему?
#FS04UK/04T / @kb --> #FS04UK/D7L / 3459 дней назад
@kb Потому что EitherT + IO == коды возврата в категории хаскеля.
#FS04UK/TRR / @pxqr --> #FS04UK/04T / 3459 дней назад
@pxqr Не понял, объясни подробнее. Какие коды возврата, что за категория хаскеля?
#FS04UK/A28 / @kb --> #FS04UK/TRR / 3459 дней назад
@pxqr > Unfortunately, I don't know of any functional language I'd call popular. I think it's because they all have dumb names like LISP and Haskell. Лол. // что такое коды возврата в категории Hawk так и не понял, видимо слишком умный для этого
#FS04UK/C3X / @kb --> #FS04UK/XYF / 3459 дней назад
@kb *Hask
#FS04UK/2A1 / @kb --> #FS04UK/C3X / 3459 дней назад
ipv6 ready BnW для ведрофона BnW на Реформале Викивач Котятки

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