为整数编写解析器 - 类型错误

Writing Parser for Integer - Type Error

给定以下 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)

Maybe (a, String) 上调用 fmap 应该将 fmap 的函数应用于 (a, String) 类型。

我错过了什么?

您需要使用 (.) 而不是 $:

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 IntegerrunParser (oneOrMore (satisfy isNumber)) 具有类型 String -> Maybe (String, String)。这两个函数可以用 (.) 组合,但是 ($) 的类型是 (a -> b) -> a -> b - 这里 aMaybe (String, a) 而你在 [=24] 中提供函数=].

如果将字符串应用于此函数,则可以获得 ($) 所需的 Maybe (String, a)