[英]is GHC's implementation of Haskell semantically broken?
今天早上我注意到一些有趣的東西,我想詢問一下它是否有重要意義。
所以在Haskell中,undefined語義包含非終止。 所以有一個功能應該是不可能的
isUndefined :: a -> Bool
因為語義會表明這解決了停止問題。
但是我相信一些GHC內置的功能允許這種限制“相當可靠”地被打破。 特別抓#。
以下代碼允許“非常可靠地”檢測到未定義的值:
import Control.Exception
import System.IO.Unsafe
import Unsafe.Coerce
isUndefined :: a -> Bool
isUndefined x = unsafePerformIO $ catch ((unsafeCoerce x :: IO ()) >> return False) ((\e -> return $ show e == "Prelude.undefined") :: SomeException -> IO Bool)
此外,這真的很重要,因為你會注意到它使用了幾個“不安全”的功能?
儒勒
編輯:有些人似乎認為我聲稱已經解決了停止問題XD我不是一個曲柄。 我只是聲明未定義的語義存在相當嚴重的中斷,因為它們聲明未定義的值應該在某種意義上與非終止無法區分。 這個功能有哪些允許。 我只是想檢查一下人們是否同意這一點以及人們對此的看法,這是否意味着在Haskell的GHC實現中添加某些不安全功能的方便性副作用是為了方便一步到位? :)
編輯:修改代碼進行編譯
我想制作三個, 啊,不 ,四個(相互關聯的)點。
不,使用unsafe...
不計算:
使用unsafeCoerce
顯然是一個破壞規則的舉動,所以回答“這真的unsafeCoerce
嗎?”這個問題:不,它不算數。 unsafe
是各種各樣的東西破壞的警告,包括語義:
isGood :: a -> Bool isGood x = unsafePerformIO . fmap read $ readFile "I_feel_like_it.txt"
> isGood '4' True > isGood '4' False
哎呀! 根據Haskell報告,破壞了語義。 哦,不,等等,我使用unsafe...
我被警告了
主要問題是使用unsafeCoerce
,您可以將其轉換為其他任何內容。 它與命令式編程中的類型一樣糟糕,因此所有類型的安全性都已經消失。
您正在catch
IOException,而不是純錯誤(⊥)。
要使用catch,您已將純錯誤undefined
轉換為IO異常。 IO
monad看似簡單,錯誤處理語義不需要使用⊥。 把它看成是像一個單子轉換,包括錯誤處理Either
在一定程度上。
與暫停問題的聯系是完全虛假的
我們不需要任何編程語言的任何不安全功能來導致這種區分非終止和錯誤。
想象一下兩個節目。 一個程序Char -> IO ()
輸出字符,另一個將第一個輸出寫入文件,然后將該文件與字符串"*** Exception: Prelude.undefined"
,並查找其長度。 我們可以運行第一個輸入undefined
或輸入'c'
。 第一個是⊥,第二個是正常終止。
哎呀! 我們通過區分未定義和非終止來解決停止問題。 哦不,等等,不,我們實際上只區分undefined
和終止。 如果我們在輸入non_terminating where non_terminating = head.show.length $ [1..]
上運行兩個程序, non_terminating where non_terminating = head.show.length $ [1..]
,我們發現第二個程序沒有終止,因為第一個沒有終止。 事實上,我們的第二個程序未能解決停機問題,因為它本身不會終止。
停止問題的解決方案更像是一個總函數halts :: (a -> IO ()) -> a -> Bool
,如果給定的函數終止於輸入a
,則總是以輸出True
結束,如果a
,則返回False
它永遠不會終止。 當你區分undefined
和error "user-defined error"
,你就不可能了,這就是你的代碼所做的。
因此,所有對暫停問題的引用都令人困惑,決定一個程序是否終止並決定是否有任何程序終止。 如果您使用上面的輸入non-terminating
而不是undefined
,則無法得出任何結論; 它在語義上已經是一個很大的延伸,可以區分非終止和undefined
,並且將其稱為停止問題的解決方案是無稽之談。
問題不是一個巨大的語義問題
基本上你的代碼所能做的就是確定你的錯誤值是使用undefined
還是其他一些錯誤產生函數生成的。 語義問題是undefined
和error "not defined with undefined"
都具有語義值⊥,但您可以區分它們。 好吧,理論上這不是很干凈,但是對於⊥的不同原因有不同的輸出對於調試是非常有用的,強制執行對值common的共同響應是瘋狂的,因為它必須始終是非終止的完全正確。
結果是任何帶有任何錯誤的程序在出現錯誤時都必須進入無限輸出循環。 這使得理論上的好處達到了深刻無益的程度。 更好的是打印*** Exception: Prelude.undefined
或Error: ungrokable wibbles
或其他有用的描述性錯誤消息。
為了在危機中有所幫助,任何編程語言都必須犧牲你的願望,使每個人的行為彼此相同。 區分不同的iss在理論上並不可愛,但在實踐中不這樣做是愚蠢的。
如果一個編程語言理論家稱這是一個嚴重的語義問題,他們就應該被戲弄,以便生活在一個程序凍結/非終止始終是無效輸入的最佳結果的世界。
來自文檔 :
高度不安全的原語
unsafeCoerce
將任何類型的值轉換為任何其他類型。 不用說,如果您使用此功能,則您有責任確保舊類型和新類型具有相同的內部表示,以防止運行時損壞。
它顯然也會破壞引用透明度,從而打破純粹性 ,因此您放棄了Haskell語義給您的所有保證。
一旦離開純凈的地形,有很多方法可以在腳下射擊自己。 您也可以使用OS原語來讀取IO
整個進程內存,從而以最糟糕的方式破壞引用透明性。
除此之外,,你的定義isUndefined
不能解決停機問題,因為它不是總 ,這意味着它不會在所有輸入終止。
例如, isUndefined (last [1..])
不會終止。
有很多程序我們可以證明它們是否終止,但這並不意味着我們已經解決了停止問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.