我通过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
(其余部分可以在页面的四分之一处阅读:http://book.realworldhaskell.org/read/code-case-study-parsing-a-binary-data-format.html)
对我来说没有任何意义的是,为什么这个功能不带任何参数?我希望它接受包含要解析的文本的Parse对象,然后返回解析的文本和新的Parse对象。相反,(我认为),它是神奇的"访问Parser,弹出一个字节,然后返回一个" modified"分析器。对象来自哪里?我现在一直盯着看了一天,仍然不知道这个功能是如何工作的。
这里的任何指导都将不胜感激。
答案 0 :(得分:6)
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
。所有这些只不过是常规功能组合的花哨包装。它从初始状态调用从{{1}}开始的输入。