Emmanuel Ch
Emmanuel Ch

Reputation: 1

Parsec and liftIO, compilation error

I'm parsing a language and I want to have syntax to $include other files while parsing.

My code:

import Text.ParserCombinators.Parsec
import Text.Parsec.Prim (parserZero)
import Text.ParserCombinators.Parsec.Char
import Control.Monad.Trans
import Data.Functor.Identity

notaInclude :: Parser [SourcesItem]
notaInclude = do
    try $ string "$Include" >> blanks1
    char '"'
    fileName <- quotedStringParser
    char '"'
    i <- getInput
    included <- liftIO $ readFile fileName
    setInput included
    si <- sources
    setInput i
    return si

The error message from GHC:

Lazi/Lazi'nh/Language/Sources/Parser.hs:65:17:
    No instance for (MonadIO Identity) arising from a use of `liftIO'
    Possible fix: add an instance declaration for (MonadIO Identity)
    In the expression: liftIO
    In a stmt of a 'do' block: included <- liftIO $ readFile fileName
    In the expression:
      do { try
             (do { string "$Include";
                   blanks1 });
           char '"';
           fileName <- quotedStringParser;
           char '"';
           .... }

How can I make it work?

Upvotes: 0

Views: 194

Answers (2)

Cactus
Cactus

Reputation: 27636

If you want to process the $include directives while parsing, you'll need to run over IO. Parsec exposes a monad transformer for this purpose called ParsecT; if you change the type of notaInclude to ParsecT String () IO [SourceItem] it should work.

However, in general I would side with @soupi's suggestion, and keep parsing pure and resolve $includes after parsing. But maybe you have some good reason to do it this way for your particular application.

Upvotes: 0

soupi
soupi

Reputation: 1013

IMO the parsing stage is not the right place to import files. I suggest you parse the file as a whole and process the result after you are done.

Upvotes: 1

Related Questions