Улучшение кода: удаление вложенных кодов и дублирование кода - PullRequest
0 голосов
/ 29 октября 2018

Я ищу отзывы о написании идиоматического кода PureScript.Этот код ниже является примером кода для чтения из API TwitterСигнатура вспомогательных методов:

-- read consumer credentials from a config file
readConfig :: String -> Aff (Either String TwitterCredentials)

-- get the bearer authentication using the consumer credentials
getTokenCredentials :: TwitterCredentials -> Aff (Either String BearerAuthorization)

-- read the Twitter API using the bearer authentication
showResults :: BearerAuthorization -> String -> Aff (Either String SearchResults)

Мой код:

main :: Effect Unit
main = launchAff_ do
  let searchTerm = "PureScript"
  config <- readConfig "./config/twitter_credentials.json"
  case config of
    Left errorStr -> errorShow errorStr
    Right credentials -> do
      tokenCredentialsE <- getTokenCredentials credentials
      case tokenCredentialsE of
        Left error ->
          errorShow error
        Right tokenCredentials -> do
          resultsE <- showResults tokenCredentials searchTerm
          case resultsE of
            Left error ->
              errorShow error
            Right result ->
              liftEffect $ logShow $ "Response:" <> (show result.statuses)

Как видите, существует множество вложенных Either операторов, и я вызываю errorShow три раза.Как бы вы написали этот код, сделав его более читабельным и, возможно, удалив дублирование кода?

1 Ответ

0 голосов
/ 29 октября 2018

Вы можете преобразовать свои вспомогательные функции из возврата Aff (Either String a) в ExceptT String Aff a. ExceptT - это монадный преобразователь, который содержит вместо значения Either e a, что означает, что ваш скомпилированный код будет выглядеть примерно так же. Но на исходном уровне вы можете игнорировать ошибки до конца и, таким образом, получать удобочитаемость и уменьшать дублирование.

Если вы управляете источником вспомогательных функций, просто перепишите их напрямую: вместо возврата Left используйте throwError, а вместо возврата Right используйте pure.

Если, с другой стороны, вы не управляете исходным кодом помощников, вы можете преобразовать их с помощью другой небольшой вспомогательной функции:

eitherToExcept :: forall e a. Aff (Either e a) -> ExceptT e Aff a
eitherToExcept action = either throwError pure <$> lift action

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

main = launchAff_ $ either errorShow (liftEffect <<< logShow) $ runExceptT do
    let searchTerm = "PureScript"
    credentials <- eitherToExcept $ readConfig "./config/twitter_credentials.json"
    tokenCredentials <- eitherToExcept $ getTokenCredentials credentials
    results <- eitherToExcept $ showResults tokenCredentials searchTerm
    pure $ "Response:" <> (show results.statuses)

P.S. Здесь и там могут быть некоторые опечатки, так как у меня не было времени компилировать и проверять код.

...