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都不會嘗試處理副作用。所以對於正確的案例來說,這確實是一個正確的抽象概念。否則,不管你做什麼,你最終都會在剛纔的提問中結束。謝謝你的幫助:) –