gpt4 book ai didi

scala - 无标签最终效果传播

转载 作者:行者123 更新时间:2023-12-01 03:08:01 24 4
gpt4 key购买 nike

tagless-final 模式让我们可以编写纯函数式程序,这些程序明确说明了它们所需的效果。

但是,扩展这种模式可能会变得具有挑战性。我将尝试用一个例子来证明这一点。想象一个简单的程序,它从数据库中读取记录并将它们打印到控制台。我们将需要一些自定义类型类 DatabaseConsole , 除了 Monad从cats/scalaz为了组合它们:

def main[F[_]: Monad: Console: Database]: F[Unit] =
read[F].flatMap(Console[F].print)

def read[F[_]: Functor: Database]: F[List[String]] =
Database[F].read.map(_.map(recordToString))

当我想向内层中的函数添加新的效果时,问题就开始了。例如,我想要我的 read如果未找到记录,则记录消息的函数

def read[F[_]: Monad: Database: Logger]: F[List[String]] =
Database[F].read.flatMap {
case Nil => Logger[F].log("no records found") *> Nil.pure
case records => records.map(recordToString).pure
}

但是现在,我必须添加 Loggerread 的所有调用者的约束上链。在这个人为的例子中,它只是 main ,但想象一下这是一个复杂的现实世界应用程序的几个层次。

我们可以从两个方面来看待这个问题:
  • 我们可以说这是一件好事,明确了我们的效果,我们确切地知道每一层需要哪些效果
  • 我们也可以说这泄露了实现细节 - main不关心日志记录,只需要 read 的结果.此外,在实际应用中,您会在顶层看到非常长的效果链。感觉就像代码的味道,但我无法确定我可以采取的其他方法。

  • 很想得到您对此的见解。

    谢谢。

    最佳答案

    We can also say that this leaks implementation details - main doesn't care about logging, it's just needs the result of read. Also, in real applications you see really long chains of effects in the top layers. It feels like a code-smell, but I can't put my finger on what other approach I can take.



    事实上,我认为事实恰恰相反。纯 FP 的关键 promise 之一是等式推理,作为从其签名推导出方法实现的一种手段。如 read需要日志效果才能完成它的业务,那么无论如何都应该在签名中声明性地表达它。明确说明您的效果的另一个好处是,当它们开始累积时,也许我们需要重新考虑这种特定方法的作用并将其拆分为更小的组件?还是这种效果真的应该用在这里?

    效果确实会叠加,但正如@TravisBrown 在评论中提到的那样,它通常是调用堆栈中最高的位置,它必须“承受实际为整个调用树提供所有隐式证据的后果”。

    关于scala - 无标签最终效果传播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54781001/

    24 4 0