Эффекты использовать для обертывания нечистых методов?

Я пытаюсь понять, как использовать эффект монады (cats.effect.IO или же scalaz.IO не имеет значения). Представьте, что у меня есть следующий метод:

def extract(str: String): String = {
    if(str.contains("123"))
        "123"
    else
        throw new IllegalArgumentException("Boom!")
}

Так как этот метод нечист (вызывает исключение), и мне нужно объединить его результат с другим эффективным вычислением (network-IO), будет хорошей практикой просто обернуть его в IO следующее:

def extract(str: String): IO[String] = IO {
    if(str.contains("123"))
        "123"
    else
        throw new IllegalArgumentException("Boom!")
}

Это общий случай использования монад Эффекта?

1 ответ

Решение

Уместно ли это или нет, зависит от того, что вы хотите выразить.

Это не как твой первый def extract(str: String): String-метод определения как-то недопустим: вы просто подметаете все исключения и побочные эффекты под ковриком, чтобы они не были видны в подписи. Если это не имеет отношения к вашему текущему проекту, и если допустимо, что программа просто аварийно завершает работу с длинной трассировкой стека брошенного исключения, то сделайте это без проблем (легко представить одноразовые одноразовые сценарии, где это будет подходящее).

Если вместо этого вы объявляете def extract(str: String): IO[String] = IO { ... }, то вы хотя бы можете увидеть в подписи, что функция extract может сделать что-то нечистое (исключение, в данном случае). Теперь возникает вопрос: кто отвечает за работу с этим исключением или где вы хотите иметь дело с этим исключением? Учтите это: если выдается исключение, оно будет появляться в вашем коде в строке, где что-то вроде yourProgram.unsafeRunSync() вызывается. Есть ли смысл иметь дело с этим исключением там? Может, да, а может и нет: никто не может тебе сказать. Если вы просто хотите поймать исключение на верхнем уровне в вашем main, войдите и exitтогда это уместно.

Однако, если вы хотите немедленно разобраться с исключением, у вас есть лучшие варианты. Например, если вы пишете метод, который запрашивает имя файла, то пытается extract что-то из этого названия, и, наконец, делает некоторые IO на файлы, то возвращаемый тип IO[String] может быть слишком непрозрачным. Вы можете использовать другую монаду (Option, Either, Try и т. д.) для представления неудачной добычи. Например, если вы используете Option[String] как тип возврата, вам больше не придется иметь дело с неясным исключением в тысяче миль от вас main метод, но вместо этого вы можете иметь дело с ним немедленно, и, например, неоднократно запрашивать новое имя файла.

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

Другие вопросы по тегам