Как бороться с монадическим возвращаемым значением `m (может быть, Foo)`? - PullRequest
4 голосов
/ 22 марта 2019

У меня есть функция, которая возвращает значение, заключенное в монаду,

produceMessage :: MonadIO m => KafkaProducer -> ProducerRecord -> m (Maybe KafkaError)

И у меня есть некоторый код для вызова этой функции, например:

err <- produceMessage prod message
return $ Right ()

Приведенный выше код былнаписанный кем-то другим, я просто пытаюсь понять, что здесь происходит.Это остальная часть функции

messageSender :: KafkaProducer -> String -> Config.KafkaP (Either KafkaError ())
messageSender prod msg = do
  message <- mkMessage Nothing (Just $ pack msg)

  err <- produceMessage prod message
  --forM_ err print
  return $ Right ()

У меня есть три конкретных вопроса:

  1. Я запутался, что означает сигнатура типа produceMessage?Ограничение типа MonadIO m, что это значит?

  2. Тип возвращаемого значения - m (Maybe KafkaError), поэтому возвращается значение Maybe, заключенное в какую монаду?

  3. Как сюда входит Right ()?В общем, я действительно не могу понять последние две строки messageSender.

1 Ответ

6 голосов
/ 22 марта 2019

Ограничение типа означает, что функцию можно использовать для возврата значения для любого типа m, который имеет экземпляр MonadIO. Как правило, это означает IO сам или стек монад, построенный поверх IO.

Значение, возвращаемое produceMessage, частично определяется вызывающей стороной . Нужно IO (Maybe KafkaError) значение? Вы можете получить это, потому что IO имеет экземпляр MonadIO. Нужна MyCustomMonadStack (Maybe KafkaError)? Вы можете получить это, если определите экземпляр MonadIO для MyCustomMonadStack.

Предположительно, Config.KafkaP также имеет экземпляр MonadIO, основанный на том, как messageSender использует produceMessage.

messageSender имеет возвращаемое значение Config.KafkaP (Either KafkaError ()). Выражение return $ Right () сначала использует Right () для получения значения типа Either KafkaError (), затем return применяется к , что для получения значения типа Config.KafkaP (Either KafkaError ()). Обратите внимание, что закомментированная строка -- forM_ err print - это единственное, что могло бы использовать значение, полученное из produceMessage, поэтому сейчас messageSender делает вид, что produceMessage сработало, независимо от того, работало оно или нет.

Более надежное определение на самом деле будет использовать возвращаемое значение produceMessage, например,

err <- produceMessage prod message

return $ case err of
           Nothing -> Right ()
           Just theError -> Left theError
...