Alex中的Haskell数据类型模式匹配

Alex中的Haskell数据类型模式匹配,haskell,compiler-construction,alex,Haskell,Compiler Construction,Alex,假设我在Haskell中有这样一个数据类型: data Token = THEN AlexPosn | ELSE AlexPosn eat_token :: Token -> [Token] -> [Token] eat_token (THEN p1)((THEN p2):rest) = rest eat_token (ELSE p1)((ELSE p2):rest) = rest 亚历克斯告诉我: data AlexPosn = AlexPn !In

假设我在Haskell中有这样一个数据类型:

data Token = THEN AlexPosn
            | ELSE AlexPosn
eat_token :: Token -> [Token] -> [Token]
eat_token  (THEN p1)((THEN p2):rest) = rest
eat_token  (ELSE p1)((ELSE p2):rest) = rest
亚历克斯告诉我:

data AlexPosn = AlexPn !Int !Int !Int
    deriving (Eq,Show)
我可以像这样进行模式匹配:

data Token = THEN AlexPosn
            | ELSE AlexPosn
eat_token :: Token -> [Token] -> [Token]
eat_token  (THEN p1)((THEN p2):rest) = rest
eat_token  (ELSE p1)((ELSE p2):rest) = rest
但我真正想做到的是:

eat_token  (_ p) tk2 = error "Syntax Error at:"++(show p)
然而,我得到:

Parse error in pattern.
有什么建议吗

eat_token  (_ p) tk2 = error "Syntax Error at:"++(show p)
Haskell不支持匿名构造函数(即使用下划线模式匹配任何构造函数),即使数据类型的所有构造函数都具有相同的元素

您可以在数据类型中使用记录字段,这将自动创建访问器函数:

data Token = THEN { src_pos :: AlexPosn }
           | ELSE { src_pos :: AlexPosn }
eat_token tok ts2 = error "Syntax Error at: " ++ (show (src_pos tok))
这将创建一个函数
src_pos
,您可以像使用任何其他函数一样使用该函数:

data Token = THEN { src_pos :: AlexPosn }
           | ELSE { src_pos :: AlexPosn }
eat_token tok ts2 = error "Syntax Error at: " ++ (show (src_pos tok))

顺便说一下,Alex(和Happy)对初学者并不特别友好。现在大多数人使用Parsec/attopassec。使用Parsec,您可以使用Haskell而不是预处理器编写解析代码

每当您发现自己想要进行忽略构造函数的模式匹配时,这通常是一种迹象,表明您想要重构您的类型,使其具有新的枚举字段,而不是旧的数据构造函数标签:

data Token = Token TokenType AlexPosn
data TokenType = THEN | ELSE
然后,您可以轻松地进行所需的模式匹配:

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

编写一个函数,从不同的标记中提取AlexPosn字段。这是Alex使用的惯用语“everyone”,但通常使用不同的命名方案(人们必须使用相同的原始示例)。枚举一种数据类型中的所有标记,然后将枚举与其源位置一起包装到另一种数据类型中。人们称包装的标记类型和源位置为“Lexeme”。