Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Parsec woes

Tags:

haskell

parsec

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]"
like image 222
Jay Avatar asked Aug 18 '13 08:08

Jay


1 Answers

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)
like image 177
MathematicalOrchid Avatar answered Nov 15 '22 10:11

MathematicalOrchid