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 "" "[email protected]"
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With