簡體   English   中英

如何讓Parsec讓我調用`read` :: Int?

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

我有以下類型檢查:

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

現在,正如函數名稱所暗示的那樣,我希望它能給我一個Int。 但如果我這樣做:

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

我收到這種類型的錯誤:

Couldn't match expected type `Int' with actual type `f0 b0'
In the return type of a call of `liftA'
In the expression:
    liftA read (many (char ' ') *> many1 digit <* many (char ' ')) ::
      Int
In an equation for `p_int':
    p_int
      = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) ::
          Int

是否有更簡單,更清晰的方法來解析可能有空格的整數? 或者解決這個問題的方法?

最終,我希望這成為以下內容的一部分:

betaLine = string "BETA " *> p_int <*> p_int  <*> p_int <*>
           p_int <*> p_parallel <*> p_exposure <* eol

這是解析看起來像這樣的行:

BETA  6 11 5 24 -1 oiiio

所以我最終可以調用一個需要這些值的BetaPair構造函數(一些作為Int,一些像其他類型,如[Exposure]和Parallel)

(如果你很好奇,這是一個文件格式的解析器,它代表蛋白質中氫鍵合的β-鏈對。我無法控制文件格式!)

如何讓Parsec讓我調用read :: Int

第二個答案是“不要使用閱讀”。

使用read相當於重新解析已經解析過的數據 - 因此在Parsec解析器中使用它是一種代碼味道。 解析自然數是無害的,但是read對Parsec有不同的失敗語義,並且它適合於Haskell的詞法語法,因此將它用於更復雜的數字格式是有問題的。

如果你不想去定義一個LanguageDef並使用Parsec的Token模塊,那么這是一個不使用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

p_int是一個生成Int的解析器,因此類型為Parser Int或類似的¹。

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

或者,您可以鍵入read函數(read :: String -> Int)來告訴編譯器表達式具有哪種類型。

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

至於更干凈的方法,考慮用spaces替換many (char ' ')

例如, ParsecT xyz Int

你可能會發現

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

做你想要的。

vanilla parsec庫似乎缺少一些明顯的解析器,這導致了“包含電池”parsec衍生包的興起。 我想parsec維護者最終會找到好東西。

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

UPDATE

或者與香草parsec:

Prelude Text.Parsec Text.Parsec.Language Text.Parsec.Token> parse ( integer . makeTokenParser $ haskellStyle ) "integer" "-1234"
Right (-1234)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM