如何在Haskell中为数据类型创建Read实例

14
所以我有一个数据类型
data SomeType a =
    Type a |
    Mix (SomeType a) (SomeType a)

这是我展示 SomeType 实例的方式

instance (Show a) => Show (SomeType a) where
    show (Type a) = show a
    show (Mix a b) = "(" ++ show a ++ " " ++ show b ++ ")"

所以

Mix (Type 5) (Type 4)

would give me

(5 4)

现在我希望有一个...
read "(3 4)" :: SomeType Int 

生产

(3 4)

或者
read "(a b)" :: SomeType Char

生产

(a b)

我不知道如何使用Read类。

顺便提一下,你的 SomeType Char 的示例并不是 show (Mix (Type 'a') (Type 'b')) 生成的内容。 - hvr
2
在类型声明之后,您可以使用 deriving (Show, Read) 来派生 ShowRead 实例。虽然它们不会产生您的输出和输入,但它们是显示(有时是读取)值的标准方式,这就是为什么您应该使用它们而不是自己的实例。如果您想以不同的方式显示它们,请使用一个单独的函数并将其命名为 render 或其他名称。 - bzn
1个回答

13

以下是一个基于文档的示例,它应该能够解析任何show渲染的内容(假设类型已定义了兼容的Read实例),也就是说read . show应该是几乎相同的:

instance (Read a) => Read (SomeType a) where
    readsPrec d r = readMix r ++ readType r
      where
        readMix = readParen True $ \r -> do
            (v1, r'') <- readsPrec d r
            (v2, r')  <- readsPrec d r''
            return (Mix v1 v2, r')

        readType r = do
            (v, r') <- readsPrec d r
            return (Type v, r')

因此,

> read "(3 4)" :: SomeType Int 
(3 4)
it :: SomeType Int

但需要注意的是,对于SomeType Char类型,默认的Show实例会用单引号将字符包围起来:

> read "('a' ('b' 'c'))" :: SomeType Char
('a' ('b' 'c'))
it :: SomeType Char
希望这能帮到你。

1
@Qin d 是包含解析上下文的运算符优先级(我不小心增加了它 - 我已经编辑过了),而 r 是当前剩余待解析的字符串。 - hvr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接