我正在通过Real World Haskell进行阅读,并且作为函子/ monads的介绍,它给出了以下示例:
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(其余部分可以在页面的四分之一处阅读: http : //book.realworldhaskell.org/read/code-case-study-parsing-a-binary-data-format.html )
对我来说没有任何意义的是,为什么这个函数不带任何参数? 我希望它接受包含要解析的文本的Parse对象,然后返回解析的文本和新的Parse对象。 相反,(我认为)它“神奇地”访问Parser,弹出一个字节,然后返回一个“修改过的”Parser。 物体来自哪里? 我一直在盯着现在一天,仍然不知道这个功能如何工作。
任何指导在这里将不胜感激。
I'm reading through Real World Haskell, and as an intro into functors/monads, it gives the following example:
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(The rest of it can be read about a quarter of the way down the page at: http://book.realworldhaskell.org/read/code-case-study-parsing-a-binary-data-format.html)
The thing that doesn't make any sense to me is, why does this function not take any parameters? I'd expect it to accept a Parse object containing the text to be parsed, then return the parsed text, and a new Parse object. Instead, (as I see it) it's "magically" accessing a Parser, popping a byte, then returning a "modified" Parser. Where does the object come from? I've been staring at at for a day now and still have no clue how this function works.
Any guidance here would be appreciated.
最满意答案
Parse类型定义为
newtype Parse a = Parse { runParse :: ParseState -> Either String (a, ParseState) }因此,如果您想知道输入来自哪里,那就是类型的定义! 每个Parse值包含一个函数,然后我们在这个例子中使用==>通过合成将两个Parse到一个新的Parse 。 然后最终使用runParse运行。 此函数需要ParseState ,定义为
data ParseState = ParseState { string :: L.ByteString , offset :: Int64 } deriving (Show)这是正在解析的字符串。
您可以将Parse类型视为该类型的别名
ParseState -> Either String (a, ParseState)这是一个你期望的功能。 随着==>函数的类型(删除了newtype包装器)
(==>) :: (ParseState -> Either String (a, ParseState)) -> (a -> (ParseState -> Either String (b, ParseState))) -> (ParseState -> Either String (b, ParseState))我们可以接受一个Parse并将它提供给另一个Parse来创建一个新的Parse 。 所有这些仅仅是围绕常规功能组合的一个奇特封装。 它从初始状态调用runParse地方获取它的输入。
The Parse type is defined as
newtype Parse a = Parse { runParse :: ParseState -> Either String (a, ParseState) }So if you're wondering where the input comes from, it's in the definition of the type! Each Parse value wraps up a function, and then we use ==> in this example to chain two Parses together through composition into a new Parse. This is then finally run using runParse. This function requires a ParseState, being defined as
data ParseState = ParseState { string :: L.ByteString , offset :: Int64 } deriving (Show)this is what carries the string being parsed.
You can think of the Parse type as an alias for the type
ParseState -> Either String (a, ParseState)which is a function like you'd expect. With the ==> function having the type (with the newtype wrapper removed)
(==>) :: (ParseState -> Either String (a, ParseState)) -> (a -> (ParseState -> Either String (b, ParseState))) -> (ParseState -> Either String (b, ParseState))we can then take one Parse and feed it into another Parse to make a new Parse. All of this is no more than a fancy wrapper around regular function composition. It gets it input from where-ever runParse is called from the initial state.
更多推荐
发布评论