Last active
December 20, 2016 01:22
-
-
Save tiqwab/0c9955dac758f98632b2efcc62906414 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE FlexibleContexts #-} | |
import Control.Monad | |
import Text.Parsec | |
import Text.ParserCombinators.Parsec hiding (try) | |
{- | |
Parsecパッケージの`manyTill`, `notFollowedBy`に関して | |
-} | |
spaceChar :: Stream s m Char => ParsecT s st m Char | |
spaceChar = char ' ' <|> char '\t' | |
skipSpaces :: Stream s m Char => ParsecT s st m () | |
skipSpaces = skipMany spaceChar | |
blankline :: Stream s m Char => ParsecT s st m Char | |
blankline = skipSpaces >> newline | |
blanklines :: Stream s m Char => ParsecT s st m String | |
blanklines = many1 blankline | |
--- | |
-- `eof`はinputの終わりとして使うことができる。 | |
-- `manyTill p end`のパースが成功するのは0以上のpのパースが成功した直後にendのパースが成功したとき。 | |
{- | |
manyTill :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a] | |
manyTill p end = scan | |
where | |
scan = do{ end; return [] } | |
<|> | |
do{ x <- p; xs <- scan; return (x:xs) } | |
-} | |
-- parseTest readCsv "col,coll,colll" | |
-- -> ["col","coll","colll"] | |
readCsv :: Stream s m Char => ParsecT s st m [String] | |
readCsv = manyTill (try ( many1 letter <* char ',') | |
<|> many1 letter) | |
eof | |
--- | |
-- `notFollowedBy p`は単体で使われるとその名前と挙動が一致せず少し理解しづらい。 | |
-- pのパースが失敗したとき、`notFollowedBy`としてのパースは成功する。また、その際にinputは消費されない。 | |
{- | |
notFollowedBy :: (Stream s m t, Show a) => ParsecT s u m a -> ParsecT s u m () | |
notFollowedBy p = try (do{ c <- try p; unexpected (show c) } | |
<|> return () | |
) | |
-} | |
-- parseTest parseSample "abc123d456efg\n" | |
-- -> ["abc","123","d","456","efg"] | |
parseSample :: Stream s m Char => ParsecT s st m [String] | |
parseSample = many (notFollowedBy closingSample >> contentSample) | |
where closingSample = blanklines | |
contentSample = many1 letter <|> many1 digit | |
main = return () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Text.Parsec | |
import Text.ParserCombinators.Parsec hiding (try) | |
{- | |
Basics of `Parsec` package. | |
-} | |
{- | |
data ParsecT s u m a | |
s: stream type | |
u: user state type | |
m: underlying monad | |
a: return type | |
type Parsec s u = ParsecT s u Identity | |
-} | |
{- | |
type GenParser tok st = Parsec [tok] st | |
type CharParser st = GenParser Char st | |
-} | |
-- This CharParser parses stream of `Char` and return `String`. | |
-- parse paren1 "paren1" "(abc)" | |
-- -> Right "abc" | |
-- parse paren1 "paren1" "abc" | |
-- -> Left "paren1" (line 1, column 1): | |
-- -> unexpected "a" | |
-- -> expecting "(" | |
paren1 :: CharParser () String | |
paren1 = do char '(' | |
x <- many letter | |
char ')' | |
return x | |
-- Applicative style of paren1. | |
paren2 :: CharParser () String | |
paren2 = char '(' *> many letter <* char ')' | |
-- Use `between`. | |
-- parse paren3 "paren3" "( 123 )" | |
-- -> Right 123 | |
paren3 :: CharParser () Int | |
paren3 = read <$> between (char '(') (char ')') (spaces *> many digit <* spaces) | |
-- Choose parser by `<|>`. Note that "aa" cannot be parsed. | |
-- parse parseWithChoice "" "ab" | |
-- -> Right "ab" | |
-- parse parseWithChoice "" "cc" | |
-- -> Left (line 1, column 1): | |
-- -> unexpected "c" | |
-- parse parseWithChoice "" "aa" | |
-- -> Left (line 1, column 1): | |
-- -> unexpected "a" | |
parseWithChoice :: CharParser () String | |
parseWithChoice = string "ab" | |
<|> string "aa" | |
<?> "parseWithChoice" | |
-- Use `try` to backtrack when a chosen parser fails. | |
-- parse parseWithTry "" "ab" | |
-- -> Right "ab" | |
-- parse parseWithTry "" "aa" | |
-- -> Right "aa" | |
parseWithTry :: CharParser () String | |
parseWithTry = try (string "ab") | |
<|> string "aa" | |
<?> "parseWithTry" | |
-- Keep State during parse. | |
-- Text.Parsec.runParser parseWithState 3 "" "2,1" | |
-- -> Right 3 | |
-- Text.Parsec.runParser parseWithState 4 "" "2,1" | |
-- -> Right 0 | |
parseWithState :: CharParser Int Int | |
parseWithState = do x <- getState | |
cols <- many alphaNum `sepBy` char ',' | |
setState (length cols) | |
modifyState (2 *) | |
y <- getState | |
if x < y | |
then return $ sum (map read cols) | |
else return 0 | |
main = return () |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment