對於複雜的GADT,GHC不能派生出Read
或Show
,所以我試圖定義低於滿足read . show == id
的自定義實例。我儘可能簡化了示例(雖然仍像我的真實代碼一樣觸發運行時錯誤)。我決定讓GHC通過爲每個GADT構造函數製作newtype
包裝器(更精確地說:對於GADT輸出的每個類型)來完成Read
和Show
實例的繁重工作。在Read
/Show
實例中,我只需讀取/顯示newtype包裝器並在必要時進行轉換。我認爲這是萬無一失的:我讓GHC定義所有不平凡的實例。但是,我似乎做錯了什麼。解析讀取時出錯
在我的真實代碼中,Foo
下面是一個複雜的GADT,GHC不會派生出Show
或Read
。由於Foo
是圍繞新類型的包裝(部分),因此我使用派生的Show
/Read
實例。
{-# LANGUAGE FlexibleContexts, FlexibleInstances, GADTs, ScopedTypeVariables #-}
import Text.Read (Read(readPrec))
newtype Bar r = Bar r deriving (Show, Read)
newtype Foo r = Foo (Bar r)
-- use the GHC-derived Show/Read for Bar
instance (Show r) => Show (Foo r) where
show (Foo x) = show x
instance (Read r) => Read (Foo r) where
readPrec = Foo <$> readPrec
此實例似乎工作:我可以打電話read . show
和我回去的輸入。 現在我有一個包裝圍繞Foo
:
data U t rep r where
U1 :: t r -> U t Int r
U2 :: t r -> U t Char r
-- use the Read/Show instances for U1Wrap and U2Wrap
newtype U1Wrap t r = U1Wrap {unU1Wrap :: t r} deriving (Show, Read)
newtype U2Wrap t r = U2Wrap (t r) deriving (Show, Read)
instance (Read (t r)) => Read (U t Int r) where
readPrec = (U1 . unU1Wrap) <$> readPrec
instance (Read (U2Wrap t r)) => Read (U t Char r) where
readPrec = do
x <- readPrec
return $ case x of
(U2Wrap y) -> U2 y
instance (Show (t r)) => Show (U t Int r) where
show (U1 x) = show $ U1Wrap x
instance (Show (t r)) => Show (U t Char r) where
show (U2 x) = show (U2Wrap x :: U2Wrap t r)
像Foo
,U
是一個複雜的GADT,所以我定義自定義NEWTYPE包裝的GADT的每個輸出類型。不幸的是,我Show
/Read
情況下不工作:
main :: IO()
main = do
let x = U1 $ Foo $ Bar 3
y = U2 $ Foo $ Bar 3
print $ show (read (show x) `asTypeOf` x)
print $ show (read (show y) `asTypeOf` y)
main
打印第一線,但我得到Exception: Prelude.read: no parse
在第二行。
這是我第一次使用Read
,所以我懷疑我做了一些不正確的事情,雖然我沒有看到那是什麼。
我的問題是:
- 爲什麼會出現這個錯誤,並邏輯我該如何解決? (有幾種方法可以捅破上面的最小示例來使錯誤消失,但我不能在我的真實代碼中執行這些操作。)
- 是否存在與GADT不同的/更好的高級方法
Read
?
如果您使用'導出實例Read(t r)=> Read(U t rep r)'?會發生什麼?那不被接受?如果將GADT定義爲只有兩個參數'tr'和'rep',並且定義了一個新類型以將't'與'r'結合起來,生活會更容易嗎? – dfeuer
@dfeuer我認爲這不適用於我的示例,但即使它的確如此,但它絕對不適用於我的真實代碼。 – crockeea
我的意思是'Show',而不是'Read'。 'Show'更容易推導出來。 – dfeuer