1

我目前正在编写有关函数式编程的演示文稿,并遇到了以下问题。

函数式编程旨在将“什么”与“如何”分开,或者更准确地说,将计算的声明与其解释分开。这就是为什么这种范式的主要焦点之一是使用可组合的数据结构来表示计算,而不对它们的执行方式做出任何假设。例如:

// Represents a computation that may fail
case class Unsafe[A,B](run: A => B)

// ...
val readIntFromFile: Unsafe[String, Int] = Unsafe { filePath => /* ... */ }
interpret(readIntFromFile)

// Interpreter
def interpret(u: Unsafe[String, Int]): Unit = {
  try {
    u.run("path/to/file")
  } catch {
    case e => /* ... */
  }
}

这似乎是有道理的,因为副作用应该只在计算执行期间而不是在其声明期间执行。问题在于,在 Scala 中,许多数据结构似乎违反了这条规则:

object Try {
  /** Constructs a `Try` using the by-name parameter.  This
   * method will ensure any non-fatal exception is caught and a
   * `Failure` object is returned.
   */
  def apply[T](r: => T): Try[T] =
    try Success(r) catch {
      case NonFatal(e) => Failure(e)
    }
}

同样适用于Futures

  /** Starts an asynchronous computation and returns a `Future` object with the result of that computation.
  *
  *  The result becomes available once the asynchronous computation is completed.
  *
  *  @tparam T       the type of the result
  *  @param body     the asynchronous computation
  *  @param executor  the execution context on which the future is run
  *  @return         the `Future` holding the result of the computation
  */
  def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = impl.Future(body)

所以,我现在想知道,是否Try真的Future是参照透明的?如果不是,那么应该如何在不依赖Successand的情况下处理错误情况Failure

4

2 回答 2

2

只要您不使用副作用,Try 是参照透明的。Try 的目的不是控制副作用,而是处理可能的异常。

如果您需要以纯粹的方式控制副作用,您可以使用来自 Cats 和 Scalaz 等库的 Task 或 IO 类型。

于 2017-06-15T13:17:00.777 回答
1

Future绝对不是 RT,因为这两个块不等价:

  1. 两个期货并行执行:

    val fa: Future[Int] = service.call
    val fb: Future[Int] = service.call
    
    for { a <- fa; b <- fb } yield a + b
    
  2. 两个期货按顺序执行:

    for { a <- service.call; b <- service.call } yield a + b
    

Try是,另一方面。处理错误的正确功能方法是使用Either[ErrorDescription, A]返回一个A但可能失败的方法(您可以使用type ErrorDescription = Throwable与 ! 等效的方法scala.util.Try)。

于 2017-06-15T13:14:38.953 回答