是否可以使用其中一個解析庫(例如Parsec
)來解析與String不同的內容?我該怎麼做?如何用Haskell解析器解析任意列表?
爲了簡單起見,我們假設輸入是一個整數的列表[Int]
。該任務可能是
- 降前導零
- 解析其餘入圖案
(S+L+)*
,其中S
是小於10的數,並且L
是一個數大於或等於10。 - 返回記錄
(Int,Int)
,其中fst
是S
和snd
的產品的清單是L
整數
的產品這將是巨大的,如果有人可以顯示如何寫這樣的解析器(或東西類似)。
是否可以使用其中一個解析庫(例如Parsec
)來解析與String不同的內容?我該怎麼做?如何用Haskell解析器解析任意列表?
爲了簡單起見,我們假設輸入是一個整數的列表[Int]
。該任務可能是
(S+L+)*
,其中S
是小於10的數,並且L
是一個數大於或等於10。(Int,Int)
,其中fst
是S
和snd
的產品的清單是L
整數的產品這將是巨大的,如果有人可以顯示如何寫這樣的解析器(或東西類似)。
是的,作爲user5402指出,Parsec
可以解析的Stream
任何情況下,包括任意列表。由於沒有預定義的令牌解析器(就像文本一樣),您必須使用例如下面的代碼自己推出(myToken
)。 tokenPrim
我唯一覺得有點尷尬的是處理「源位置」。 SourcePos
是一個抽象類型(而不是類型類),迫使我使用它的「文件名/行/列」格式,這在這裏感覺有點不自然。
總之,這裏是代碼(無前導零的跳躍,爲了簡潔)
import Text.Parsec
myToken :: (Show a) => (a -> Bool) -> Parsec [a]() a
myToken test = tokenPrim show incPos $ justIf test where
incPos pos _ _ = incSourceColumn pos 1
justIf test x = if (test x) then Just x else Nothing
small = myToken (< 10)
large = myToken (>= 10)
smallLargePattern = do
smallints <- many1 small
largeints <- many1 large
let prod = foldl1 (*)
return (prod smallints, prod largeints)
myIntListParser :: Parsec [Int]() [(Int,Int)]
myIntListParser = many smallLargePattern
testMe :: [Int] -> [(Int, Int)]
testMe xs = case parse myIntListParser "your list" xs of
Left err -> error $ show err
Right result -> result
嘗試了這一切:
*Main> testMe [1,2,55,33,3,5,99]
[(2,1815),(15,99)]
*Main> testMe [1,2,55,33,3,5,99,1]
*** Exception: "your list" (line 1, column 9):
unexpected end of input
注意尷尬的行/列格式錯誤消息
當然可以寫一個函數sanitiseSourcePos :: SourcePos -> MyListPosition
很有可能有一種方法可以讓Parsec使用[a]
作爲流類型,但解析器組合器背後的想法其實非常簡單,並且它不是很難推出自己的庫。
我推薦的非常方便的資源是由Graham Hutton和Erik Meijer提供的Monadic Parsing in Haskell。確實,現在Erik Meijer在edx.org (link)上講授了一個介紹Haskell /函數式編程課程,講座7講述了所有關於函數式解析器的內容。正如他在介紹了講座規定:
」 ......沒有一個可以遵循努力掌握函數式編程,而無需編寫自己的解析器組合庫的路徑首先,我們要解釋解析器是什麼,以及他們如何能自然被視爲副作用的功能。接下來,我們定義了一些基本的解析器和高階函數的結合爲解析器。......」