我希望实现一个read实例,它使我能够读取一个字符串(例如:"- -“--8-3 -")并构造一个包含这些值的列表。
data Value a = Nul | Val a
showsValue :: (Show a) => Value a -> ShowS
showsValue (Val x) = ("Value" ++) . shows x
showsValue (Nul) = ("Nothing 0" ++)
instance Show a => Show (Value a) where
showsPrec _ x = showsValue x
instance Read a => Read (Value a) where
readsPrec _ m = readsMatrix m
readsMatrix :: (Read a) => ReadS (Value a)
readsMatrix ('-':s) = [(Nul, rest) | (' ',rest) <- reads s]
readsMatrix s = [(Val x,rest)| (x,' ':rest) <- reads s]在执行此测试之后:
read "- 8 - - 3" :: Value Int我得到了错误*** Exception: Prelude.read: no parse
我在这里做错什么了?
更新
readsMatrix ('-':s) = [(Nul, dropWhile isSpace s)]
readsMatrix s = [(Val x, dropWhile isSpace rest) | (x,rest) <- reads s]发布于 2012-11-25 20:00:24
校正值a的读取
首先,不要费心移除空格,这都是由reads处理的。
readsMatrix :: (Read a) => ReadS (Value a)
readsMatrix ('-':s) = [(Nul, dropWhile (==' ') s)]
readsMatrix s = [(Val x,rest)| (x,rest) <- reads s] 您的读取实例现在可以用于单个值:
*Main> read "4" :: Value Int
Value4
*Main> read "-" :: Value Int
Nothing 0校正值a的读取
但是,您希望将列表以空格分隔,因此,由于这是非标准行为,因此需要编写自定义readList :: :: ReadS [Value a]
instance Read a => Read (Value a) where
readsPrec _ m = readsMatrix m
readList s = [(map read.words $ s,"")]所以现在
*Main> read "- 4 2 - 5" :: [Value Int]
[Nothing 0,Value4,Value2,Nothing 0,Value5]但不幸的是,
*Main> read "- 4 2 \n- 5 4" :: [Value Int]
[Nothing 0,Value4,Value2,Nothing 0,Value5,Value4]更糟的是,
*Main> read "- 4 2 \n- 5 4" :: [[Value Int]]
*** Exception: Prelude.read: no parse读取矩阵
没有简单的方法可以绕过这个问题,因为在readListOfLists类中没有Read,那么为什么不创建一个独立的函数呢?
matrix :: Read a => String -> [[Value a]]
matrix = map read.lines所以
*Main> matrix "3 4 -\n3 - 6\n4 5 -" :: [[Value Int]]
[[Value3,Value4,Nothing 0],[Value3,Nothing 0,Value6],[Value4,Value5,Nothing 0]]表演不是我想要的
我认为Show实例对于Value有点误导(Nul没有零,Val不是写的Value)。要么写
data Value a = Nul | Val a deriving Show以便它看起来像现在一样,或者定义它来匹配Read实例。
instance Show a => Show (Value a) where
show Nul = "-"
show (Val a) = show a发布于 2012-11-25 19:01:44
在您的readsMatrix函数中,
readsMatrix ('-':s) = [(Nul, rest) | (' ',rest) <- reads s]这意味着在使用'-'之后,输入字符串的其余部分被传递给
reads :: ReadS Char但是Read实例Char需要一个单引号括起来的字符,比如'h'。
要在结果中获得一个元素(' ',rest),您需要--在它之前的可选空格之后--字符序列'\'' : ' ' : '\'' : whatever。你的预期输入中没有这些。您想要做的是在'-'之后移除空格,所以如果空格是可选的,并且可能有多个字符长,
readsMatrix ('-':s) = [(Nul, dropWhile isSpace s)]工作(如果换行符、制表符等也被忽略的话)。如果您只想要一个强制空间,模式应该是
readsMatrix ('-':' ':s) = [(Nul, s)]第二方程
readsMatrix s = [(Val x,rest)| (x,' ':rest) <- reads s]可以按原样工作,但要求值后面跟着一个空格,例如,readMatrix "3" :: [(Value Int, [Char])]将返回一个空列表。
我想你也希望有空间可选,所以也许
readsMatrix s = [(Val x, dropWhile isSpace rest) | (x,rest) <- reads s]是您想要的,但是由于reads忽略了大多数类型的前导空格,
readsMatrix s = [(Val x, rest) | (x, rest) <- reads s]也许会更好。
但是,在'-'之前,您并没有忽略前面的空格,所以也需要这样做。
也许实现更好地使用
lex :: ReadS String在Prelude中,将字符串拆分为大致遵循Haskell语法的标记。
ghci> lex "(12 + 34) abc"
[("(","12 + 34) abc")]除开括号外,从其余部分中分离出令牌"12"等。
一种可能是使用lex,从而使前导空格被适当忽略
readsMatrix s = do
(tok, rest) <- lex s
case tok of
"-" -> return (Nul, rest)
_ -> case reads tok of
[(x,"")] -> return (Val x, rest)
_ -> []最后,
read "- 8 - - 3" :: Value Int即使这样也会导致*** Exception: Prelude.read: no parse,因为只有在转换后的令牌后面只有空格时,read才会成功,但是在转换初始'-'之后,在其余的输入中仍然会有四个可转换的令牌。
read "- 8 - - 3" :: [Value Int]另一方面,应该是成功的。
https://stackoverflow.com/questions/13553794
复制相似问题