首页 > 解决方案 > 如何使用`flatMap`实现延迟计算的成本估算?

问题描述

我已经实现了一个带有Calculation2 个参数的类:一个计算输入,它是一个按名称调用的参数,也是一个成本。当我尝试flatMap计算时,它的第一部分被执行。是否有可能推迟一切flatMap并仍然提供总成本?

class Calculation[+R](input: => R, val cost: Int = 0) {
    def value: R = input

    def map[A](f: R => A): Calculation[A] =
        new Calculation(f(input), cost)

    def flatMap[A](f: R => Calculation[A]): Calculation[A] = {
        val step = f(input)
        new Calculation(step.value, cost + step.cost)
    }
}

object Rextester extends App {
    val f1 = new Calculation({
        println("F1")
        "F1"
    })

    val f2 = f1.flatMap(s => new Calculation({
        println("F2")
        s + " => F2"
    }))

    println(f2.cost)
}

一旦f2被声明(flatMap被调用),我们可以看到将打印“F1”。打印的成本是"15",这是正确的,但我希望完全推迟实际计算,这意味着我f1在计算成本时不应该看到正在执行的操作。

标签: scalamonads

解决方案


您只需要多一点懒惰,这样就不会急切地评估成本flatMap

class Calculation[+R](input: => R, c: => Int = 0) {
  def value: R = input
  lazy val cost: Int = c

  def map[A](f: R => A): Calculation[A] =
    new Calculation(f(input), cost)

  def flatMap[A](f: R => Calculation[A]): Calculation[A] = {
    lazy val step = f(value)
    new Calculation(step.value, cost + step.cost)
  }
}

请注意,这可能仍然不具有您想要的语义(例如f2.value,连续调用两次将导致两者都F1F2打印,第一次打印,并且仅第二次打印),但它确实可以防止在定义F2时发生副作用。f2


推荐阅读