我有:
data Time a = NoTime | Time a
我想按規則轉換它:
NoTime -> Nothing
Time a -> Just a
Time a并且Maybe a是同構型別(是嗎?),但似乎我無法強制Time a(Maybe a由于“自定義型別錯誤”)。什么是最優雅,也許是最短的方法(不是簡單的case)?
uj5u.com熱心網友回復:
Data.Coerce.coerce需要的不僅僅是同構。它只能導航新型別的包裝器。您有兩種不相關的型別,它們恰好具有相同的表示形式,并且coerce對此無能為力。
unsafeCoerce可能會起作用,但這顯然是不安全的,而且我認為不能保證具有相似結構的型別必須以相同的方式表示。
uj5u.com熱心網友回復:
如果您不明智地決定使用unsafeCoerce.
unsafeCoerce對于一個Time a值來回一個值來說,它是“足夠安全的” Maybe a。這依賴于 GHC 在記憶體中的布局Time a和Maybe a完全相同的方式,即使沒有技術保證,當前版本的 GHC 也會這樣做,而且很難想象這種行為會在未來的版本中改變。
不過,您需要注意一些事項。首先,您需要確保Time' 的定義在結構上與Maybe' 相同。在base中,我們有:
data Maybe a = Nothing | Just a
所以我們必須有確切的定義:
data Time a = NoTime | Time a
如果建構式的順序相反,它將不起作用。結果將是不正確的結果或運行時崩潰:
data BadTime a = Time a | NoTime -- WILL NOT WORK!
另外,直接使用也是很危險的unsafeCoerce。以下似乎可行:
main = print (unsafeCoerce (Just 1) :: Time Int)
通過列印Time 1,但型別錯誤。Just 1默認的型別為Maybe Integer,實際上不能安全地unsafeCoerced 為 a Time Int。它恰好適用于“小”整數,如果您嘗試強制轉換為不同的數字型別,它將完全失敗。這個:
main = print (unsafeCoerce (Just 1) :: Time Double)
列印Time 5.0e-324,例如。
因此,您需要撰寫帶有強制型別引數相等的型別簽名的“安全”包裝器,a以便安全地使用這種不安全的強制:
toTime :: Maybe a -> Time a
toTime = unsafeCoerce
fromTime :: Time a -> Maybe a
fromTime = unsafeCoerce
如果你必須撰寫包裝器,你最好使用安全版本,因為你只需要撰寫一次:
toTime :: Maybe a -> Time a
toTime Nothing = NoTime
toTime (Just x) = Time x
fromTime :: Time a -> Maybe a
fromTime NoTime = Nothing
fromTime (Time x) = Just x
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/517151.html
標籤:哈斯克尔
