Как я уже упоминал в своем комментарии, проблема в том, что в ошибочной строке:
stringHandler :: Handler String
stringHandler = liftIO $ fmap (\s -> (fromMaybe (throwError err404) s)) ioMaybeString
s
- это Maybe String
, поэтому использовать его в качестве второго аргумента для fromMaybe
, первый аргумент должен быть String
- и throwError
никогда не будет генерировать строку.
Хотя вы говорили о том, что ваш код, возможно, слишком многословен, и вы бы посмотрели на его упрощение позже, я думаю, что часть проблема здесь в том, что в этом конкретном обработчике вы пытаетесь быть слишком сжатым. Давайте попробуем написать это в более простом c, псевдо-императивном стиле. Поскольку Handler
является монадой, мы можем записать это в блок do
, который проверяет значение s
и выполняет соответствующее действие:
stringHandler :: Handler String
stringHandler = do
s <- liftIO ioMaybeString
case s of
Just str -> return str
Nothing -> throwError err404
Обратите внимание, что throwError
может выдавать значение типа Handler a
для любого типа, который в данном случае должен быть String
. И что мы должны использовать liftIO
на ioMaybeString
, чтобы поднять его в Handler
монаду, иначе это не будет проверкой типов.
Я могу понять, почему вы могли подумать, что fromMaybe
было хорошим подходит здесь, но, по сути, это не так - причина в том, что это «чистая» функция, которая вообще не включает ввод-вывод, тогда как когда вы говорите о выдаче ошибок на сервере, вы совершенно неизбежно делаете ввод-вывод. Эти вещи по сути не могут смешиваться в одной функции. (Что также делает fmap
неуместным - это, безусловно, может быть использовано для «поднятия» чистого вычисления для работы над действиями ввода-вывода, но здесь, как я уже сказал, вычисление, которое вам принципиально необходимо, не является чистым.)
И если вы хотите сделать приведенную выше функцию stringHandler
более краткой, хотя я не думаю, что это действительно улучшение, вы все равно можете явно использовать >>=
вместо блока do
, не делая код слишком нечитабельно:
stringHandler = liftIO ioMaybeString >>= f
where f (Just str) = return str
f Nothing = throwError err404