鉴于以下Parser
定义(来自Brent Yorgey教授的宾夕法尼亚大学class):
newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }
satisfy :: (Char -> Bool) -> Parser Char
satisfy p = Parser f
where
f [] = Nothing -- fail on the empty input
f (x:xs) -- check if x satisfies the predicate
-- if so, return x along with the remainder
-- of the input (that is, xs)
| p x = Just (x, xs)
| otherwise = Nothing -- otherwise, fail
给出one or more of 'a'
的以下解析器:
oneOrMore :: Parser a -> Parser [a]
oneOrMore p = (:) <$> p <*> (zeroOrMore p)
而且,现在我想提取Integer
或者什么都没有:
parseInteger :: String -> Maybe Integer
parseInteger = fmap (read . fst) $ runParser (oneOrMore (satisfy isNumber))
但是我收到了这个编译时错误:
JsonParser.hs:42:36:
Couldn't match type ‘(String, b0)’ with ‘Maybe ([Char], String)’
Expected type: String -> (String, b0)
Actual type: String -> Maybe ([Char], String)
In the second argument of ‘($)’, namely
‘runParser (oneOrMore (satisfy isNumber))’
In the expression:
fmap (read . fst) $ runParser (oneOrMore (satisfy isNumber))
Failed, modules loaded: SExpr, Model, AParser.
*SExpr Data.Char> :t runParser
runParser :: Parser a -> String -> Maybe (a, String)
我感到困惑,因为runParser
的类型为String -> Maybe (a, String)
。
在fmap
上呼叫Maybe (a, String)
应将fmap
的功能应用于(a, String)
类型。
我错过了什么?
答案 0 :(得分:3)
您需要使用(.)
代替$
:
fmap (read . fst) . runParser (oneOrMore (satisfy isNumber))
或者您需要将字符串提供给runParser
:
parseInteger s = fmap (read . fst) $ runParser (oneOrMore (satisfy isNumber)) s
在这种情况下, fmap (read . fst)
的类型为Maybe (String, a) -> Maybe Integer
,runParser (oneOrMore (satisfy isNumber))
的类型为String -> Maybe (String, String)
。这两个函数可以由(.)
组成,但($)
的类型为(a -> b) -> a -> b
- 此处a
为Maybe (String, a)
,而您在{{1}内提供函数}}
如果您将字符串应用于此功能,则可以获得Parser
所需的Maybe (String, a)
。