Yes, as user5402 points out, it Parseccan parse any instance Stream, including arbitrary lists. Since there are no predefined parsers-parsers (as for text), you need to collapse your own ( myTokenbelow), using, for example, tokenPrim
The only thing that seems a little inconvenient to me is the processing of the "initial positions". SourcePosis an abstract type (and not a type class) and forces me to use its "filename / line / column" format, which is a bit unnatural here.
Anyway, here is the code (without missing leading zeros, for brevity)
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
I tried everything:
*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
Note the inconvenient row / column format in the error message
, sanitiseSourcePos :: SourcePos -> MyListPosition