应用式Parsec的问题

时间:2015-02-23 04:38:01

标签: haskell parsec

我有以下ADT:

type Program = [Expr]
data Expr =
    Num Int
    | Bool Bool
    | Binding String Expr
    deriving (Show)

这是一个lhs is rhs形式的变量绑定表达式解析器。

binding :: Parser Expr
binding = do
    lhs <- word
    spaces
    string "is"
    spaces
    rhs <- expr
    return $ Binding lhs rhs

它工作正常,但是当我尝试将其转换为应用风格时,它会产生错误的结果。

binding :: Parser Expr
binding = Binding <$> word <* (spaces *> string "is" *> spaces) *> expr

在带括号的部分中用*>替换>>也不起作用。这两种实现之间的区别是什么?是否有一个组合器用于组合两个解析器并忽略两者的结果?

尝试使用Debug.trace调试也没有...没有打印任何内容。

binding :: Parser Expr
binding = (\x y -> trace (show (x, y)) (Binding x y)) <$> word <* (spaces *> string "is" *> spaces) *> expr

解析器的其余部分,用于上下文:

word :: Parser String
word = many1 letter

expr :: Parser Expr
expr = binding <|> atom

program :: Parser Program
program = do
    spaces
    result <- many (expr <* spaces)
    return result

2 个答案:

答案 0 :(得分:10)

您的问题是<$><*>等是关联的。这意味着您的行:

binding = Binding <$> word <* (spaces *> string "is" *> spaces) *> expr

将被解释为

binding = (Binding <$> word <* (spaces *> string "is" *> spaces)) *> expr

这意味着它将解析然后忽略最后一个expr之前的所有内容。正如@icktoofay所说,您可以将预期版本编写为:

binding = Binding <$> word <* spaces <* string "is" <* spaces <*> expr

并且根本不需要任何括号,因为左边的关联性。

答案 1 :(得分:6)

@danem是对的,试试:

binding :: Parser Expr
binding = Binding <$> word <*> (spaces *> string "is" *> spaces *> expr)

完整来源:http://lpaste.net/121011

您的原始定义以这种方式解析:

binding = ((Binding <$> word) <* (spaces *> string "is" *> spaces)) *> expr

即。它的格式为something *> expr,因此返回的值仅由最后expr确定。解析了lhs和is令牌,但随后将其丢弃。

以下是子表达式类型检查的方法:

Binding                     :: String -> Expr -> Expr
(Binding <$> word)          :: Parser (Expr -> Expr)
(Binding <$> word) <* (...) :: Parser (Expr -> Expr)

所以我们看到所有类型的检查都是由于currying以及我们放弃了something的结果这一事实。