簡體   English   中英

為什么Haskell異常只能在IO monad中捕獲?

[英]Why can Haskell exceptions only be caught inside the IO monad?

任何人都可以解釋為什么異常可能會被拋出IO monad,但可能只會被捕獲到它內部?

其中一個原因是Haskell指稱語義

(純)Haskell函數的一個簡潔屬性是它們的單調性 - 更明確的參數產生更多定義的值。 這個屬性非常重要,例如推理遞歸函數(閱讀文章以了解原因)。

根據定義表示異常是底部, _|_ ,poset中對應於給定類型的最小元素。 因此,為了滿足單調性要求,以下不等式需要適用於Haskell函數的任何表示f

f(_|_) <= f(X)

現在,如果我們可以捕獲異常,我們可以通過“識別”底部(捕獲異常)並返回更多定義的值來打破這種不等式:

f x = case catch (seq x True) (\exception -> False) of
        True -> -- there was no exception
            undefined
        False -> -- there was an exception, return defined value
            42

這是完整的工作演示(需要base-4 Control.Exception):

import Prelude hiding (catch)
import System.IO.Unsafe (unsafePerformIO)
import qualified Control.Exception as E

catch :: a -> (E.SomeException -> a) -> a
catch x h = unsafePerformIO $ E.catch (return $! x) (return . h)

f x = case catch (seq x True) (\exception -> False) of
        True -> -- there was no exception
            undefined
        False -> -- there was an exception, return defined value
            42

正如TomMD指出的那樣,另一個原因是打破了參考透明度。 你可以用相同的東西取代平等的東西,得到另一個答案 (在指稱意義上相等,即它們表示相同的值,而不是==意義。)

我們怎么做? 請考慮以下表達式:

let x = x in x

這是一個非終止遞歸,因此它永遠不會返回任何信息,因此也由_|_ 如果我們能夠捕獲異常,我們可以編寫函數f,如

f undefined = 0
f (let x = x in x) = _|_

(對於嚴格的函數,后者總是如此,因為Haskell沒有提供檢測非終止計算的方法 - 原則上不能,因為Halting問題 。)

因為異常破壞參照透明度

您可能正在討論實際上直接輸入結果的異常。 例如:

head [] = error "oh no!" -- this type of exception
head (x:xs) = x

如果你感到遺憾的是無法捕獲這樣的錯誤,那么我告訴你,函數不應該依賴於error或任何其他異常,而應該使用正確的返回類型( MaybeEither ,或MonadError )。 這迫使您以更明確的方式處理異常情況。

與上述不同(以及導致問題背后的問題),異常可以來自諸如內存條件完全獨立於計算值的信號。 這顯然不是一個純粹的概念,必須存在於IO中。

我的解釋可能有問題,但這就是我理解的方式。

由於函數在Haskell中是純粹的,因此編譯器有權按照他希望的任何順序對它們進行求值,並且它仍然會產生相同的結果。 例如,給定的功能:

square :: Int -> Int
square x = x * x

表達square (square 2)可以用不同的方式進行評估,但它總是減少到相同的結果,即16。

如果我們從其他地方打電話給square

test x = if x == 2 
         then square x 
         else 0

當實際需要值時,可以在test函數“外部”評估square x 在那一刻,調用堆棧可能與您在Java中所期望的完全不同。

因此,即使我們想捕捉square拋出的潛在異常,您應該在哪里放置catch部分?

暫無
暫無

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

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