How do I get Parsec to let me call `read` :: Int?

前端 未结 3 1826
感情败类
感情败类 2020-12-21 15:50

I\'ve got the following, which type-checks:

p_int = liftA read (many (char \' \') *> many1 digit <* many (char \' \'))

Now, as the fu

相关标签:
3条回答
  • 2020-12-21 16:19

    You may find

    Text-Megaparsec-Lexer.integer :: MonadParsec s m Char => m Integer
    

    does what you want.

    The vanilla parsec library seems to be missing a number of obvious parsers, which has led to the rise of "batteries included" parsec derivative packages. I suppose the parsec maintainers will get around to betteries eventually.

    https://hackage.haskell.org/package/megaparsec-4.2.0/docs/Text-Megaparsec-Lexer.html

    UPDATE

    or with vanilla parsec:

    Prelude Text.Parsec Text.Parsec.Language Text.Parsec.Token> parse ( integer . makeTokenParser $ haskellStyle ) "integer" "-1234"
    Right (-1234)
    
    0 讨论(0)
  • 2020-12-21 16:21

    p_int is a parser that produces an Int, so the type would be Parser Int or similar¹.

    p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) :: Parser Int
    

    Alternatively, you can type the read function, (read :: String -> Int) to tell the compiler which type the expression has.

    p_int = liftA (read :: String -> Int) (many (char ' ') *> many1 digit <* many (char ' ')) :: Int
    

    As for the cleaner ways, consider replacing many (char ' ') with spaces.

    ¹ ParsecT x y z Int, for example.

    0 讨论(0)
  • 2020-12-21 16:24

    How do I get Parsec to let me call read :: Int?

    A second answer is "Don't use read".

    Using read is equivalent to re-parsing data you have already parsed - so using it within a Parsec parser is a code smell. Parsing natural numbers is harmless enough, but read has different failure semantics to Parsec and it is tailored to Haskell's lexical syntax so using it for more complicated number formats is problematic.

    If you don't want to go to the trouble of defining a LanguageDef and using Parsec's Token module here is a natural number parser that doesn't use read:

    -- | Needs @foldl'@ from Data.List and 
    -- @digitToInt@ from Data.Char.
    --
    positiveNatural :: Stream s m Char => ParsecT s u m Int
    positiveNatural = 
        foldl' (\a i -> a * 10 + digitToInt i) 0 <$> many1 digit
    
    0 讨论(0)
提交回复
热议问题