读取时解析错误
Parse error when reading
GHC 无法为复杂的 GADT 导出 Read
或 Show
,因此我尝试在下面定义满足 read . show == id
的自定义实例。我尽可能地简化了示例(同时仍然像我的真实代码一样触发运行时错误)。我决定让 GHC 为每个 GADT 构造函数制作 newtype
包装器(更准确地说:为每个 type 由 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,因此我为 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
,所以我怀疑我做错了什么,虽然我看不出那是什么。
我的问题是:
- 为什么我会收到此错误,逻辑上我该如何解决? (有几种方法可以戳上面的最小示例来使错误消失,但我不能在我的真实代码中做那些事情。)
- 是否有 different/better 高级方法来
Read
ing GADT?
您为 Foo
自定义的 Show
实例括号不正确。
> U2 $ Foo $ Bar 3
U2Wrap Bar 3
编写自定义 Show
实例时,您应该改为定义 showsPrec
。那是因为 show
只是返回一个独立于上下文的字符串,而 showsPrec
基于优先级插入括号。有关更多文档,请参阅 Text.Show
。
instance (Show r) => Show (Foo r) where
showsPrec n (Foo x) = showsPrec n x
在这里有效。
我不知道有什么优雅的方法可以自动为我们获取此 GADT
的 Read
实例。派生机制似乎无法弄清楚每个 rep
只需要考虑一个构造函数。
这里至少可以推导出Show
。我还在此处包括一个手动 Read
实例,我希望它符合 Show
。我试图模仿 Text.Read
中的定义,您也可以在其他情况下这样做。或者,可以使用 -ddump-deriv
GHC 参数查看派生的 Read
实例,并尝试在自定义代码中复制它们。
{-# LANGUAGE GADTs, StandaloneDeriving, FlexibleInstances, FlexibleContexts #-}
import Text.Read
import Data.Proxy
data U t rep r where
U1 :: t r -> U t Int r
U2 :: t r -> U t Char r
deriving instance Show (t r) => Show (U t rep r)
instance Read (t r) => Read (U t Int r) where
readPrec = parens $ do
prec 10 $ do
Ident "U1" <- lexP
U1 <$> readPrec
instance Read (t r) => Read (U t Char r) where
readPrec = parens $ do
prec 10 $ do
Ident "U2" <- lexP
U2 <$> readPrec
GHC 无法为复杂的 GADT 导出 Read
或 Show
,因此我尝试在下面定义满足 read . show == id
的自定义实例。我尽可能地简化了示例(同时仍然像我的真实代码一样触发运行时错误)。我决定让 GHC 为每个 GADT 构造函数制作 newtype
包装器(更准确地说:为每个 type 由 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,因此我为 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
,所以我怀疑我做错了什么,虽然我看不出那是什么。
我的问题是:
- 为什么我会收到此错误,逻辑上我该如何解决? (有几种方法可以戳上面的最小示例来使错误消失,但我不能在我的真实代码中做那些事情。)
- 是否有 different/better 高级方法来
Read
ing GADT?
您为 Foo
自定义的 Show
实例括号不正确。
> U2 $ Foo $ Bar 3
U2Wrap Bar 3
编写自定义 Show
实例时,您应该改为定义 showsPrec
。那是因为 show
只是返回一个独立于上下文的字符串,而 showsPrec
基于优先级插入括号。有关更多文档,请参阅 Text.Show
。
instance (Show r) => Show (Foo r) where
showsPrec n (Foo x) = showsPrec n x
在这里有效。
我不知道有什么优雅的方法可以自动为我们获取此 GADT
的 Read
实例。派生机制似乎无法弄清楚每个 rep
只需要考虑一个构造函数。
这里至少可以推导出Show
。我还在此处包括一个手动 Read
实例,我希望它符合 Show
。我试图模仿 Text.Read
中的定义,您也可以在其他情况下这样做。或者,可以使用 -ddump-deriv
GHC 参数查看派生的 Read
实例,并尝试在自定义代码中复制它们。
{-# LANGUAGE GADTs, StandaloneDeriving, FlexibleInstances, FlexibleContexts #-}
import Text.Read
import Data.Proxy
data U t rep r where
U1 :: t r -> U t Int r
U2 :: t r -> U t Char r
deriving instance Show (t r) => Show (U t rep r)
instance Read (t r) => Read (U t Int r) where
readPrec = parens $ do
prec 10 $ do
Ident "U1" <- lexP
U1 <$> readPrec
instance Read (t r) => Read (U t Char r) where
readPrec = parens $ do
prec 10 $ do
Ident "U2" <- lexP
U2 <$> readPrec