如何为简单的自定义数据格式执行Read实例

时间:2016-09-16 22:36:29

标签: haskell

我试图使用简短易读的格式来显示和读取我的数据,我希望它可以从Haskell解释器中使用,以便在写入时手写或复制粘贴输入我尝试新功能。

我的数据是一个Int数字列表,每个都有一个布尔属性,我与+-关联,是第一个默认值,所以它不需要显式表示(与通常的符号一样)。我想在数字后面代表-,就像在这个例子中一样:

[2, 5-, 4, 0-, 1, 6-, 2-]

请注意,我无法使用常规符号,因为我需要能够将-分配给0,以便0-0不同(同样,可能在将来我需要使用负数,例如[-4-, -2])。

我做了简单的部分,即定义列表术语的数据类型并实现show函数。

data Term = T Int Bool deriving (Eq)

instance Show Term where
    show (T v True)   = show v
    show (T v False)  = show v ++ "-"

我不知道如何执行相应的read功能,或者我是否不能使用-符号,因为它是Haskell语言的标志。欢迎提出建议。

2 个答案:

答案 0 :(得分:2)

尝试这样的事情:

instance Read Term where
  readsPrec n s = do
    (i,rest) <- readsPrec (n+1) s       -- read `i :: Int`
    return $ case rest of               -- look at the rest of the string
      ('-':rest') -> (T i False, rest') -- if it starts with '-'...
      rest' -> (T i True, rest')        -- if it doesn't...
Haskell中的

Read密切关注解析器可以由类型String -> [(a, String)]表示的类型(此类型被赋予类型同义词ReadS。要熟悉解析的这种想法,我建议阅读以下functional pearl on monadic parsing

然后,来自GHCi:

ghci> read "[2, 5-, 4, 0-, 1, 6-, 2-]" :: [Term]
[2,5-,4,0-,1,6-,2-]

答案 1 :(得分:1)

我非常喜欢Alec的答案,我接受了。但经过阅读,思考和尝试,我达成了另一个非常简单的解决方案,我想在此分享。

它使用reads代替readsPrec,因为Term构造函数不是中缀,因此我们不需要管理优先级,而且它不是monadic。

instance Read Term where
  readsPrec _ s = 
    [(T v False, rest)  | (v, '-' : rest) <- reads s] ++ 
    [(T v True , rest)  | (v,       rest) <- reads s]

对应Show实例的对称性值得注意:

instance Show Term where
  show (T v True)   = show v
  show (T v False)  = show v ++ "-"