Question

I need to parse fixed length fields with attoparsec but im now struggling with the compiler. Im still a newbie, the code below is the closest solution I have:

> {-# LANGUAGE OverloadedStrings #-}
> import Control.Applicative
> import Data.Text as T
> import Data.Attoparsec.Combinator
> import Data.Attoparsec.Text hiding (take)
> import Data.Char
> import Prelude hiding (take)
>
> type City = Text
> type Ready = Bool
> data CityReady = CR City Ready deriving Show
>
> input = T.unlines ["#London              1",
>                    "#Seoul               0",
>                    "#Tokyo               0",
>                    "#New York            1"]
>
> parseCityReady = many $ CR <$> cityParser <*> readyParser <* endOfLine
>
> cityParser = char '#' *>
>              takeTill isSpace <*
>              skipWhile isHorizontalSpace
>
>
> readyParser = char '1' *> pure True  <|> char '0' *> pure False
>
> main =
>   case parseOnly parseCityReady input of
>      Left err  -> print err
>      Right xs  -> mapM_ print xs
>

This is all great but it is only returning Cities without spaces.

CR "London" True
CR "Seoul" False
CR "Tokyo" False

I have tried using applicative to take 20 characters for the City text string

> cityParser = char '#' *>
>              take 20

and even do syntax

> cityParser = do char '#'
>                 city <- take 20
>                 return city

but both approaches fail to compile with this error:

Couldn't match expected type `attoparsec-0.10.4.0:Data.Attoparsec.Internal.Types.Parser
                                Text b0'
            with actual type `Text -> Text'
In the return type of a call of `take'
Probable cause: `take' is applied to too few arguments
In the second argument of `(*>)', namely `take 20'
In the expression: char '#' *> take 20

What is causing the ghc to ask for Text -> Text when the take has a type of Int -> Text -> Text?

How do I solve it in both applicative and do-syntax?

Was it helpful?

Solution

So, your problem is that you are hiding several versions of the take function. In particular, you are hiding the take from attoparsec rather than the take function from the Text module. All you should need to do is change your imports like so

> import Control.Applicative
> import Data.Attoparsec.Combinator
> import Data.Attoparsec.Text
> import Data.Char
> import Data.Text as T hiding (take)
> import Prelude hiding (take)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top