Question

I am trying to learn Parsec and am trying to parse a simple email address. I tried the following code. My expected output is the entire email address as a string. But when I run the code, I only get ".com" Could somene please tell me whats going on?

{-# LANGUAGE NoMonomorphismRestriction #-}

import Text.Parsec
import Control.Applicative hiding ((<|>))

email = many1 alphaNum
     *> char '@'
     *> many1 alphaNum
     *> string ".com"

emailstr = parse email "" "xxxx@yyy.com"
Était-ce utile?

La solution

The type signature for *> says it returns the result from the second parser, and throws away the result from the first parser. Thus, email returns only the result from the final parser in the sequence.

What you probably want is something more like

email =
  stitch
    <$> many1 alphaNum
    <*> char '@'
    <*> many1 alphaNum
    <*> string ".com"

This runs the four parsers and passes the result of each as an argument to stitch. If you write a suitable implementation for stitch:

stitch a b c d = a ++ [b] ++ c ++ d

then you should get back your string.

Notice that at this point, you could also put the username and domain into separate fields of a data structure or something:

data Email = Email {username, domain :: String}

email =
  Email
    <$> many1 alphaNum
    <*  char '@'
    <*> ((++) <$> many1 alphaNum <*> string ".com")

Now your parser returns an Email structure rather than just a plain string. That might not be what you're after, but it demonstrates how to write a more sophisticated parser.

All of this is using the Applicative interface to Parsec, which is generally considered good style. The other way to use Parsec is the Monad interface:

email = do
  a <- many1 alphaNum
  b <- char '@'
  c <- many1 alphaNum
  d <- string ".com"
  return (a ++ [b] ++ c ++ d)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top