1

我目前正在进行关于函数式编程的演示,并且遇到了以下问题。斯卡拉的尝试是否透明?

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

// 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) 

所以,我现在想知道,是TryFuture真透明的?如果不是,那么如何处理错误情况而不依赖于SuccessFailure

回答

2

只要您不使用副作用,尝试是引用透明的。 Try的目的不是为了控制副作用,而是为了处理可能的例外。

如果您需要以纯粹的方式控制副作用,您可以使用Cat和Scalaz等库中的任务或IO类型。

+0

非常酷的答案。我从来没有想过像这样尝试。 –

+0

我还会补充一点:我觉得大多数时候,'Try'是错误的抽象,而'Either'和'IO'更准确。 –

+1

@FrancisToth我认为这或多或少是正确的。 '尝试'基本上就像声明“抛出异常”。这比根本不记录错误情况要好,但除此之外不会给你任何额外的信息,而且不像'Either'它要求你的错误情况是一个例外。另一方面,“IO/Task”处理完全不同的问题。 – puhlen

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但可能失败的方法(对于scala.util.Try,您可以使用type ErrorDescription = Throwable!)。

+0

这就是我没有得到的。为什么尝试引用透明?关于在文件中执行写操作的尝试呢?这绝对是一种“可观察的与外部世界的互动”,对吗?那么,从纯FP的角度来看,我们不应该停止依靠模式匹配尝试? –

+1

'Option' RT?对于在文件中执行写操作的'Option [Unit]'怎么办? – OlivierBlanvillain

+0

上面的答案是有道理的,Option和Try都不会尝试处理副作用。所以对于正确的案例来说,这确实是一个正确的抽象概念。否则,不管你做什么,你最终都会在刚才的提问中结束。谢谢你的帮助:) –