Slavomir Kaslev | 6 Oct 17:38

I want my free (and good looking) parser!

I am writing a Parsec parser for a C-like language and I have several datas that
look more or less like this one:

> import Control.Monad( liftM )
> import Text.ParserCombinators.Parsec

> data FooBar = Foo | Bar
>             deriving (Show,Read,Bounded,Enum)

Looking at these, it seems that there should be no need to write a parser for
this guy by hand. We already know that it is bounded and enumerable, so we can
get a list of all possible FooBars:

> enumAll :: (Bounded a, Enum a) => [a]
> enumAll = enumFromTo minBound maxBound

Also, we know how to show and read each FooBar. Therefore, I should get a free
parser!

> freeParser :: (Enum a, Bounded a, Show a, Read a) => Parser a

Here is one use of freeParser:

> paramMod = option Foo freeParser
> test = parseTest $ do { x <- paramMod; eof; return x }

Not suprisingly:
test "Foo"  => Foo
test "Bar"  => Bar
test ""     => Foo
(Continue reading)

Christian Maeder | 6 Oct 19:07
Favicon

Re: I want my free (and good looking) parser!

Slavomir Kaslev wrote:
>> freeParser = freeParser' minBound
>>     where enumAll' :: (Bounded a, Enum a) => a -> [a]
>>           enumAll' _ = enumAll
>>           freeParser' :: (Enum a, Bounded a, Show a, Read a) => a -> Parser a
>>           freeParser' x = liftM read $ choice (map (string . show) (enumAll' x))

1. I would use an explicit function argument instead of "Show" to allow
strings starting with lower case.

2. Calling read after parsing looks stupid. Just return the value shown
as parser result (within map).

3. Instead of the "string" parser, it should be checked if a further
alphaNum or '_' follows (for the longest match). And don't forget "try"!

Cheers Christian

> [Actually, in my code I use reserved' (reserved' x = reserved x >> return x)
> instead of string, where reserved is from Parsec's builtin tokenizer (which does
> some neat things behind the curtains). Here string is used just to
> illustrate the
> expamle.]
> 
> The problem is that freeParser, although useful, is far from elegant. It's
> something that I came up with by trial and error. In short: it's a hack.
> 
> I would like to hear your suggestions about how it can be beautified.
> 
> Thank you in advance.
(Continue reading)

Slavomir Kaslev | 6 Oct 19:20

Re: I want my free (and good looking) parser!

On Mon, Oct 6, 2008 at 8:07 PM, Christian Maeder
<Christian.Maeder <at> dfki.de> wrote:
> Slavomir Kaslev wrote:
>>> freeParser = freeParser' minBound
>>>     where enumAll' :: (Bounded a, Enum a) => a -> [a]
>>>           enumAll' _ = enumAll
>>>           freeParser' :: (Enum a, Bounded a, Show a, Read a) => a -> Parser a
>>>           freeParser' x = liftM read $ choice (map (string . show) (enumAll' x))
>
> 1. I would use an explicit function argument instead of "Show" to allow
> strings starting with lower case.
>

You are right. But that was not the problem. The problem was that I
wrestled with Haskell's type system quite a bit to make freeParser
work. What I want to write is

freeParser :: (Enum a, Bounded a, Show a, Read a) => Parser a
freeParser = liftM read $ choice (map (string . show) enumAll)

but it doesn't compile. How can I make this piece code work?

> 2. Calling read after parsing looks stupid. Just return the value shown
> as parser result (within map).
>

Good point. It is silly =-)

> 3. Instead of the "string" parser, it should be checked if a further
> alphaNum or '_' follows (for the longest match). And don't forget "try"!
(Continue reading)

Jeremy Shaw | 6 Oct 20:13
Favicon

Re: Re: I want my free (and good looking) parser!

At Mon, 6 Oct 2008 20:20:57 +0300,
Slavomir Kaslev wrote:
> 
> On Mon, Oct 6, 2008 at 8:07 PM, Christian Maeder
> <Christian.Maeder <at> dfki.de> wrote:
> > Slavomir Kaslev wrote:
> >>> freeParser = freeParser' minBound
> >>>     where enumAll' :: (Bounded a, Enum a) => a -> [a]
> >>>           enumAll' _ = enumAll
> >>>           freeParser' :: (Enum a, Bounded a, Show a, Read a) => a -> Parser a
> >>>           freeParser' x = liftM read $ choice (map (string . show) (enumAll' x))
> >
> > 1. I would use an explicit function argument instead of "Show" to allow
> > strings starting with lower case.
> >
> 
> You are right. But that was not the problem. The problem was that I
> wrestled with Haskell's type system quite a bit to make freeParser
> work. What I want to write is
> 
> freeParser :: (Enum a, Bounded a, Show a, Read a) => Parser a
> freeParser = liftM read $ choice (map (string . show) enumAll)
> 
> but it doesn't compile. How can I make this piece code work?

I would start by adding this to the top of the file:

> {-# LANGUAGE ScopedTypeVariables, FlexibleContexts  #-}

Then add 'forall a.' to the type signature of freeParser. This causes
(Continue reading)


Gmane