解析器示例不是与我点击

Car*_*ate 3 monads haskell

我正在阅读Real World Haskell,作为仿函数/ monad的介绍,它给出了以下示例:

parseByte :: Parse Word8
parseByte =
    getState ==> \initState ->
    case L.uncons (string initState) of
      Nothing ->
          bail "no more input"
      Just (byte,remainder) ->
          putState newState ==> \_ ->
          identity byte
        where newState = initState { string = remainder,
                                     offset = newOffset }
              newOffset = offset initState + 1
Run Code Online (Sandbox Code Playgroud)

(其余部分可以在页面的四分之一处阅读:http://book.realworldhaskell.org/read/code-case-study-parsing-a-binary-data-format.html)

对我没有任何意义的是,为什么这个功能不带任何参数?我希望它接受包含要解析的文本的Parse对象,然后返回解析的文本和新的Parse对象.相反,(我认为)它"神奇地"访问Parser,弹出一个字节,然后返回一个"修改过的"Parser.对象来自哪里?我一直盯着看了一天,仍然不知道这个功能是如何工作的.

这里的任何指导将不胜感激.

bhe*_*ilr 6

Parse类型定义为

newtype Parse a = Parse
    { runParse :: ParseState -> Either String (a, ParseState)
    }
Run Code Online (Sandbox Code Playgroud)

因此,如果您想知道输入来自哪里,那就是类型的定义!每个Parse值都包含一个函数,然后我们==>在这个例子中使用Parse通过组合将两个s链接到一个新的Parse.然后最终使用runParse.此函数需要a ParseState,被定义为

data ParseState = ParseState
    { string :: L.ByteString
    , offset :: Int64
    } deriving (Show)
Run Code Online (Sandbox Code Playgroud)

这是携带正在解析的字符串的内容.

您可以将Parse类型视为该类型的别名

ParseState -> Either String (a, ParseState)
Run Code Online (Sandbox Code Playgroud)

这是一个你期望的功能.使用==>具有类型的函数(删除newtype包装器)

(==>)
    ::       (ParseState -> Either String (a, ParseState))
    -> (a -> (ParseState -> Either String (b, ParseState)))
    ->       (ParseState -> Either String (b, ParseState))
Run Code Online (Sandbox Code Playgroud)

然后我们可以拿一个Parse并将它喂给另一个Parse来制作一个新的Parse.所有这些只不过是常规功能组合的花哨包装.它runParse从初始状态调用where-ever得到输入.