用于包装不纯方法的效果?

问题描述 投票:1回答:1

我试图了解如何使用效果monad(cats.effect.IOscalaz.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!")
}

它是Effect monads的常见用例吗?

scala functional-programming scalaz effects scala-cats
1个回答
2
投票

这是否合适取决于您想表达的内容。

这不像你的第一个def extract(str: String): String方法定义在某种程度上是无效的:你只是扫描地毯下的所有异常和副作用,以便它们在签名中不可见。如果这与您当前的项目无关,并且如果一个程序只是因为抛出的异常的长堆栈跟踪崩溃是可以接受的,那么就这样做,没有问题(很容易想象一次性丢弃的脚本,这将是适当)。

如果你声明def extract(str: String): IO[String] = IO { ... },那么你至少可以在签名中看到函数extract可以做一些不纯的事情(在这种情况下抛出异常)。现在问题变成:谁负责处理这个异常,或者你想在哪里处理这个异常?考虑一下:如果抛出异常,它将出现在调用yourProgram.unsafeRunSync()之类的行中的代码中。在那里处理这个例外是否有意义?也许它确实如此,也许它没有:没有人能告诉你。如果您只想在main的顶层捕获异常,请记录它和exit,那么它是合适的。

但是,如果您想立即处理异常,那么您有更好的选择。例如,如果您正在编写一个提示输入文件名的方法,那么尝试使用此名称输入extract,最后对文件执行一些IO,然后返回类型IO[String]可能太不透明。您可能想要使用其他一些monad(OptionEitherTry等)来表示失败的提取。例如,如果你使用Option[String]作为返回类型,你不再需要在千里之外的main方法中处理一个模糊的异常,而是你可以立即处理它,例如,反复提示输入一个新的文件名。

整个练习有点类似于提出如何处理一般异常的策略,只有在这里你才能在方法的类型签名中明确表达它。

© www.soinside.com 2019 - 2024. All rights reserved.