自定义Haskell Read实例解析行为不一致的原因是什么?
解析行为不一致的原因
首先明确Haskell中read的默认实现逻辑:它依赖reads的结果,只会从reads返回的列表里筛选出剩余字符串为空的解析项。如果有且仅有一个符合条件的项,就返回对应的值;否则抛出no parse错误。
按照你给出的Read Foo实例,reads ""返回[]是符合预期的——因为空字符串无法匹配前缀"Foo",所以没有解析结果。但read ""却返回Foo,这大概率是以下原因之一:
- GHCi缓存未更新:如果你在GHCi中修改了
Read实例但没有执行:r重新加载代码,可能出现reads使用新实例、read却沿用旧实例(比如之前自动派生的Read实现)的情况。重新加载代码就能解决这个问题。 - 实例实现的隐性错误:检查你的
readsPrec代码是否真的符合预期。比如是否不小心把List.stripPrefix "Foo"写成了List.stripPrefix ""——这种情况下,任何输入都会匹配空前缀,reads ""会返回[(Foo, "")],自然read ""就会返回Foo。 - 极端罕见的版本兼容问题:某些非常旧的GHC版本对
Read类的默认实现可能有特殊处理,但这种情况几乎不会遇到。
另外,补充一个规范的Read Foo实例写法,它会处理带括号的解析场景(比如read "(Foo)"也能正确解析),同时保证空输入的行为符合预期:
import qualified Data.List as List import Text.Read (readParen, appPrec) data Foo = Foo instance Show Foo where show _ = "Foo" instance Read Foo where readsPrec p = readParen (p > appPrec) $ \s -> case List.stripPrefix "Foo" s of Just rest -> [(Foo, rest)] Nothing -> []
内容的提问来源于stack exchange,提问作者Thomas Eding
相关产品推荐
相关产品推荐

