[Haskell-beginners] parsec and a never terminating parser

Adam Flott adam at adamflott.com
Wed Mar 25 21:53:46 UTC 2015


On Wed, 25 Mar 2015 17:10:00 -0400
David McBride <toad3k at gmail.com> wrote:

> The problem is your show instance.
> 
> show x' = show x', means that when x' is a FullState, it shows it, which
> causes an infinite loop.
> 
> You need to take out the default case and add something for FullState.
> 

Doh! Nice catch. Thanks David!

For those keeping track, here's how to fix such a case:

    instance Show x => Show (FieldState x) where
        show (EmptyState)   = "empty ('-')"
        show (OmittedState) = "omitted ('^')"
        show (OtherState)   = "other ('~')"
        show (FullState x') = show x'


> On Wed, Mar 25, 2015 at 11:37 AM, Adam Flott <adam at adamflott.com> wrote:
> 
> > I'm having trouble understanding why my simple parser never terminates when
> > specific input is used.
> >
> > For example, let's say the first column is a field which can be in one of 4
> > states, empty, omitted, other, and any arbitrary value. That is,
> >
> >     data FieldState a = EmptyState | OmittedState | OtherState | FullState
> > a
> >       deriving (Eq, Ord)
> >
> > When attempting to use,
> >
> >     $ echo "- " | ./parser
> >     "- \n"
> >     empty ('-')
> >     $ echo "^ " | ./parser
> >     "^ \n"
> >     omitted ('^')
> >     $ echo "~ " | ./parser
> >     "~ \n"
> >     other ('~')
> >     [ all of this is as expected ]
> >     $ echo "1 " | ./parser
> >     "1 \n"
> >     [ computer twiddles it's thumbs here until I manually terminate it ...
> > ]
> >     ^C^C
> >     $
> >
> > Does anyone know what's happening and now to alleviate it?
> >
> >
> > -- begin full code --
> >
> > -- base
> > import Control.Applicative
> > import Data.Word
> >
> > -- Hackage
> > import qualified Data.Text.Lazy as TL
> > import qualified Data.Text.Lazy.IO as TLIO
> > import Text.Parsec (parse)
> > import Text.Parsec.Text.Lazy (Parser)
> > import Text.Parser.Combinators
> > import Text.Parser.Char
> >
> > data FieldState a = EmptyState | OmittedState | OtherState | FullState a
> >   deriving (Eq, Ord)
> >
> > instance Functor FieldState where
> >     fmap f (FullState a)    = FullState (f a)
> >     fmap _ EmptyState       = EmptyState
> >     fmap _ OmittedState     = OmittedState
> >     fmap _ OtherState       = OtherState
> >
> > instance Applicative FieldState where
> >     pure = FullState
> >     (FullState f) <*> (FullState x) = FullState (f x)
> >     _             <*> _             = EmptyState
> >
> > instance Monad FieldState where
> >     (FullState x) >>= k = k x
> >     EmptyState    >>= _ = EmptyState
> >     OmittedState  >>= _ = OmittedState
> >     OtherState    >>= _ = OtherState
> >
> >     (FullState _) >> k = k
> >     EmptyState    >> _ = EmptyState
> >     OmittedState  >> _ = OmittedState
> >     OtherState    >> _ = OtherState
> >
> >     return  = FullState
> >     fail _  = EmptyState
> >
> > instance Show (FieldState x) where
> >     show (EmptyState)   = "empty ('-')"
> >     show (OmittedState) = "omitted ('^')"
> >     show (OtherState)   = "other ('~')"
> >     show x' = show x'
> >
> > data Counter = Counter Word64 deriving (Eq, Ord, Show)
> >
> > parseNum :: (Num a) => Parser a
> > parseNum = do
> >     n <- rd <$> many digit
> >     return $ fromIntegral n
> >     where rd = read :: String -> Integer
> >
> > parseCounter :: Parser Counter
> > parseCounter = Counter <$> parseNum
> >
> > parseFieldStateOff :: Parser Char
> > parseFieldStateOff = char '-'
> >
> > parseFieldStateOmitted :: Parser Char
> > parseFieldStateOmitted = char '^'
> >
> > parseFieldStateOther :: Parser Char
> > parseFieldStateOther = char '~'
> >
> > parseFieldState :: Parser a -> Parser (FieldState a)
> > parseFieldState p = (parseFieldStateOff >> return EmptyState)
> >                   <|> (parseFieldStateOmitted >> return OmittedState)
> >                   <|> (parseFieldStateOther >> return OtherState)
> >                   <|> (p >>= return . FullState)
> >
> > main :: IO ()
> > main = do
> >     ls <- TLIO.getContents
> >     print ls
> >     mapM_ processLine (TL.lines ls)
> >
> > processLine :: TL.Text -> IO ()
> > processLine line = case (parse (parseFieldState parseCounter) "" line) of
> >   Left err -> print err
> >   Right xs -> print xs
> >
> > _______________________________________________
> > Beginners mailing list
> > Beginners at haskell.org
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> >
> >


-- 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://mail.haskell.org/pipermail/beginners/attachments/20150325/883e9636/attachment.sig>


More information about the Beginners mailing list