为什么haskell使用一种ReadS来表示一个函数?

cod*_*e4j 5 haskell function

我正在阅读的源代码reads.reads被定义为reads :: Read a => ReadS a 它只是返回ReadS a而a必须是一个实例Read.

并且ReadS a被定义为type ReadS a = String -> [(a, String)],所以返回的东西reads只是一个函数,它接受一个字符串并返回一个元组数组.

然后我想知道为什么reads没有ReadS 定义a.就像 reads :: Read a => (String -> [(a, String)])

Jon*_*rdy 11

事物的解析器
是从字符串

事物和字符串列表的函数!

- 各种来源

它有助于推理程序在其意图方面考虑抽象,而不是实现.所以是的,然而type ReadS a = String -> [(a, String)],这是解决事物的实际目标和将ReadS解析器链接在一起的次要因素.正如Rhymoid指出:

composeReads :: ReadS a -> ReadS b -> ReadS (a,b)
Run Code Online (Sandbox Code Playgroud)

传达解析器组合的意图,并且作为一个快乐的副作用比内联等效更简洁:

composeReads
  :: (String -> [(a, String)])
  -> (String -> [(b, String)])
  -> (String -> [((a, b), String)])
Run Code Online (Sandbox Code Playgroud)

分解这种重复是一件好事而且显而易见的事情,不仅仅是因为避免重复是有益的,而且还要尽可能多地增加每行有用语义内容的数量.如果我们想要改变这些解析器的实现方式,那么将它们封装在这个别名后面是一小步,可以让我们避免对每个使用站点进行大量更改.

您可以在各种解析器组合库中重复这一点,例如Parsec,Attoparsec和uu-parsinglib.一个Parser是一个Parser是一个Parser,而更像是一个黑盒子这些东西,越容易与它们的使用发挥和implementation- 分开.