gpt4 book ai didi

haskell - 如何在 Haskell 中实现实际解​​析已经完成的 Read 实例?

转载 作者:行者123 更新时间:2023-12-04 18:31:32 24 4
gpt4 key购买 nike

this answer , 人们发现执行 Read 不会很困难的声明数据类型 Tree 的实例,实际解析已经完成。

但是,我很难理解 read 这样的功能是如何实现的。作品:AFAIK,我应该实现 readsPrec函数而不是 read这个readsPrec应该对仅包含一个字符的字符串执行读取。这个对吗?
如果是这样,那么应该如何实现 Read Tree 的实例当通过 ParsecT 完成解析时?我们可以逐字打破解析,还是有必要这样做?

没想到read作为 Haskell 中的一个困难功能,但现在我发现它非常困惑和困惑,我在搜索中迷失了 Hoogle对于 readP_to_S 等所有不熟悉的事物, readS , ETC。

任何帮助或引用将不胜感激。

最佳答案

我一直在想这个问题,你的问题促使我研究它。

摘要:最简单的手动操作方法:

instance Read Tree where
readsPrec _ str = [(parsecRead str,"")]

但是 deriving是更安全的选择;以上不适用于 [Tree]和其他数据类型。我的理解是 ShowRead不打算手动实现 ;他们 应派生并在 上工作语法正确的 Haskell 表达式 .

看起来像 Read 的原因不是那么简单
class Read a where
read :: String -> a

是有一个解析器组合器系统,类似于但不同于 Parsec,它被设计为模块化、递归等。但是由于我们已经在使用不同的解析器组合库 Parsec,我认为最好尽可能少地干扰其他系统。

Prelude 文档说 Read 的最小完整实现是 readsPrecreadPrec .后者被描述为“建议使用新式解析器替换 readsPrec(仅限 GHC)”。这对我来说有点麻烦,所以让我们开始实现 readsPrec .

类型是
readsPrec :: Read a => Int -> ReadS a
type ReadS a = String -> [(a,String)]

以及 ReadS 的文档读取“类型 a 的解析器,表示为接受 String 并返回可能解析列表为 (a,String) 对的函数”。对我来说,“解析”是什么并不完全清楚,但看看 source code for read in Text.Read 揭示:
read :: Read a => String -> a
read s = either errorWithoutStackTrace id (readEither s)

readEither :: Read a => String -> Either String a
readEither s =
-- minPrec is defined as 0 in Text.ParserCombinators.ReadPrec
case [ x | (x,"") <- readPrec_to_S read' minPrec s ] of
[x] -> Right x
[] -> Left "Prelude.read: no parse"
_ -> Left "Prelude.read: ambiguous parse"
where
read' = -- read' :: P.ReadPrec a
do x <- readPrec
lift P.skipSpaces -- P is Text.ParserCombinators.ReadP
return x

我试图扩展 readPrec_to_S 的定义等等,但我觉得不值得。我认为定义清楚地表明我们应该返回 [(x,"")]作为一个成功的解析。
readsPrec 的整数参数似乎是“优先上下文”。我的猜测是,如果我们只想一次解析一棵树,忽略它是安全的,但是如果我们尝试解析 [Tree] 的实例,忽略它会导致问题。例如。我会忽略它,因为我认为这不值得麻烦。

简而言之,如果我们有 parsecRead :: String -> Tree如您所指的帖子中所定义(作者称之为 read' )
instance Read Tree where
readsPrec _ str = [(parsecRead str,"")]

如果我们检查它在程序中是如何工作的(使用原始询问者提供的 Show 实例):
main = do
print (read "ABC(DE)F" == example)
print ([read "ABC(DE)F", read "ABC(DE)F"] :: [Tree])
print (read "[ABC(DE)F,ABC(DE)F]" :: [Tree])

我们得到
True
[ABC(DE)F,ABC(DE)F]
Test.hs: Prelude.read: no parse

这里的复杂性和缺乏文档实际上让我认为 deriving (Read)实际上是唯一安全的选择,除非您愿意深入了解优先级的细节。
我想我在某处读过 ShowRead实际上是 主要意在派生 ,并且这些字符串应为 语法正确的 Haskell 表达式 (如果我错了,请纠正我)。对于更一般的解析, Parsec 等库可能是更好的选择。

如果你有精力自己研究源代码,相关模块似乎是
  • Text.Read
  • GHC.Read
  • Text.ParserCombinators.ReadP
  • Text.ParserCombinators.ReadPrec
  • 关于haskell - 如何在 Haskell 中实现实际解​​析已经完成的 Read 实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38815948/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com