0

Suppose I have a data type in Haskell like this:

data Token = THEN AlexPosn
            | ELSE AlexPosn

from Alex, I get that:

data AlexPosn = AlexPn !Int !Int !Int
    deriving (Eq,Show)

I am able to do pattern matching like this:

eat_token :: Token -> [Token] -> [Token]
eat_token  (THEN p1)((THEN p2):rest) = rest
eat_token  (ELSE p1)((ELSE p2):rest) = rest

But what I really want to accomplish here is this:

eat_token  (_ p) tk2 = error "Syntax Error at:"++(show p)

However, I get:

Parse error in pattern.

Any suggestions?

Alberto_Saavedra
  • 389
  • 1
  • 2
  • 12

2 Answers2

2

Whenever you find yourself wanting to do pattern matching that ignores the constructor like that, it's usually a sign that you want to refactor your type to have a new enumeration field instead of the old data constructor labels:

data Token = Token TokenType AlexPosn
data TokenType = THEN | ELSE

Then, you can easily do the pattern match you wanted:

eat_token (Token _ p) tk2 = error $ "Syntax Error at: " ++ show p
hammar
  • 138,522
  • 17
  • 304
  • 385
  • 1
    This is the idiom "everyone" uses with Alex but usually with a different naming scheme (people must be working from the same original example). Enumerate all the tokens in one data type then wrap the enumeration in another data type along with its source position. People call the wrapped token type and source position "Lexeme". – stephen tetley Feb 27 '12 at 13:45
0
eat_token  (_ p) tk2 = error "Syntax Error at:"++(show p)

Haskell does not support anonymous constructors (i.e. using underscores to pattern match any constructor) even if all the constructors of a data type have the same elements.

You can use record fields in your datatype, this will automatically create an accessor function:

data Token = THEN { src_pos :: AlexPosn }
           | ELSE { src_pos :: AlexPosn }

This creates a function src_pos which you can use like any other function:

eat_token tok ts2 = error "Syntax Error at: " ++ (show (src_pos tok))

By the way Alex (and Happy) aren't particularly beginner friendly. Most people use Parsec / Attoparsec nowadays. With Parsec you write the parsing code in Haskell rather than with a preprocessor.

stephen tetley
  • 4,465
  • 16
  • 18