簡體   English   中英

函數式編程:如何處理函數式編程中的異常或其等價物

[英]Functional Programming: How to handle exceptions in Functional Programming or what is its equivalent

假設,我有以下代碼。

public int divide(int dividend, int divisor) {
    if( divisor == 0 || (dividend == Integer.MIN_VALUE && divisor == -1)) 
          throw new DivisionException();
    return dividend/divisor;
}

如何在函數式編程中寫這個?

我有一個類似於上述用 Java 編寫的邏輯,並希望將其遷移到 Haskell/Clojure 中的功能代碼。 如何在divide的調用者中處理這個?

我知道上面的代碼是完全必要的 它的編寫並沒有考慮將來將其遷移到 FP。

請用HaskellClojure 中的示例代碼為我提供建議。

下面展示了如何在 Haskell 中做到這一點。

根據上式siginure divide :: Int -> Int -> Either [Char] Int你可以看到,功能divide將返回一個Left stringRight Int

Either代數數據結構,還有更多,您可以編寫自己的數據結構

divide :: Int -> Int -> Either [Char] Int
divide dividend divisor
    | (divisor == 0) = Left "Sorry, 0 is not allowed :o"
    | (dividend == (minBound :: Int)) && (divisor == -1) = Left "somethig went wrong"
    | otherwise = Right (dividend `div` divisor)

main = do
    print (divide 4 2)                     -- Right 2
    print (divide 4 0)                     -- Left "Sorry, 0 is not allowed :o"
    print (divide (minBound :: Int) (-1))  -- Left "somethig went wrong"

你可以在repl.it上玩它

在 Haskell 中,您可以使用error "and your error message"拋出錯誤,但這會使您的程序崩潰……這不是我們想要的。

divide函數不是全數:其輸入域中的某些值沒有圖像。

使函數總計

更改輸出域,使其可以返回錯誤或數字。 調用者負責檢查該值是否真的是一個數字,還是一個錯誤。

在像 Clojure 這樣的動態類型語言中,您可以返回nil ,但任何其他值也可以工作,只要您能將它與數字區分開來。 在像 Haskell 這樣的靜態類型語言中,如果需要,可以使用Data.Either或您自己的數據類型。

  • 該檢查在 Haskell 中以一致且靜態的方式完成。 您必須每次都進行檢查,即使您確定除數不能為空。 但是,您也可以擁有一個包裝函數must-divide ,它會在出現錯誤時引發異常。

  • 在 Clojure 中,您可能會忘記檢查nil ,這可能是由於錯誤或因為您比編譯器擁有更多關於除數的信息。 但是,您可以通過導出需要您考慮錯誤路徑的divide宏來強制進行一致檢查:

     (divide xy :on-error (throw ...)) (divide xy :on-error default-value)

    ...可以分別擴展為:

     (or (maybe-divide xy) (throw ...)) (or (maybe-divide xy) default-value)

    ...與

    (defn maybe-divide [dividend divisor] (and (not (zero? divisor)) (or (not= Integer/MIN_VALUE dividend) (not= -1 divisor)) (/ dividend divisor)))

拋出異常

數學運算被組合成更大的表達式:在其中添加顯式錯誤處理路徑可能很快變得不可讀。 此外,您可能希望您的大部分操作使用有效輸入調用divide ,並且不想在每次調用時檢查結果是否有效(例如,某些數學方程帶有證明除數不可能永遠為空)。 在這種情況下,Clojure 和 Haskell 支持異常。 這允許您在有錯誤的情況下在調用堆棧中捕獲更高的錯誤。

在 Clojure 中,這與 Java 並沒有什么不同:

(defn divide
  [dividend divisor]
  (if (or (zero? divisor)
          (and (= Integer/MIN_VALUE
                  dividend)
               (= -1 divisor)))
    (throw (DivisionException.))
    (/ dividend divisor)))

您的代碼不會改變任何變量,因此已經非常實用。 異常也是 Clojure 的一部分,因為它采用了 JVM 的執行模型。

在 Clojure(script) 中,您可以使用Failjure庫,它提供了一種以純函數方式處理異常的方法。

(ns stackoverflow
    (:require
      [failjure.core :as f]))

(defn divide
  [dividend divisor]
  (cond
    (zero? divisor) (f/fail "The divisor is 0; unable to perform operation.")
    (and (= Integer/MIN_VALUE dividend) (neg? divisor)) (f/fail "Unable to perform division with a negative dividend and divisor")
    :else (/ dividend divisor)))

(f/fail ..)將返回一個 Failure 對象,您可以將其用於錯誤處理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM