Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 将语法生成转换为Parsec_Parsing_Haskell_Functional Programming_Parsec_Left Recursion - Fatal编程技术网

Parsing 将语法生成转换为Parsec

Parsing 将语法生成转换为Parsec,parsing,haskell,functional-programming,parsec,left-recursion,Parsing,Haskell,Functional Programming,Parsec,Left Recursion,我正在尝试转换以下语法产品 callExpr: primaryExpr | callExpr primaryExpr 到Haskell中的Parsec表达式 显然,问题在于它是左递归的,所以我尝试用递归上升的方式来解析它。我试图实现的伪代码是: e = primaryExp while(true) { e2 = primaryExp if(e2 failed) break; e = CallExpr(e, e2) } 我试图将此翻译成Haskell: ca

我正在尝试转换以下语法产品

callExpr:
    primaryExpr
  | callExpr primaryExpr
到Haskell中的Parsec表达式

显然,问题在于它是左递归的,所以我尝试用递归上升的方式来解析它。我试图实现的伪代码是:

e = primaryExp
while(true) {
    e2 = primaryExp
    if(e2 failed) break;
    e = CallExpr(e, e2)
}
我试图将此翻译成Haskell:

callExpr :: IParser Expr
callExpr = do
    e <- primaryExpr
    return $ callExpr' e
  where
    callExpr' e = do
        e2m <- optionMaybe primaryExpr
        e' <- maybe e (\e2 -> callExpr' (CallExpr e e2)) e2m
        return e'
但是,这给了我以下类型错误:

Couldn't match type `ParsecT String () (State SourcePos) t0'
              with `Expr'
Expected type: ParsecT String () (State SourcePos) Expr
  Actual type: ParsecT
                 String
                 ()
                 (State SourcePos)
                 (ParsecT String () (State SourcePos) t0)
In a stmt of a 'do' block: return $ callExpr' e
In the expression:
  do { e <- primaryExpr;
       return $ callExpr' e }
In an equation for `callExpr':
    callExpr
      = do { e <- primaryExpr;
             return $ callExpr' e }
      where
          callExpr' e
            = do { e2m <- optionMaybe primaryExpr;
                   .... }
无法匹配类型'ParsecT String()(State SourcePos)t0'
带“Expr”
预期类型:ParsecT String()(State SourcePos)Expr
实际类型:ParsecT
一串
()
(State SourcePos)
(解析字符串()(状态SourcePos)t0)
在'do'块的stmt中:返回$callExpr'e
在表达式中:
不要使用。
chainl1p op
以左关联方式解析一个或多个由
op
-s分隔的
p
-s。
op
返回一个二进制函数,用于将两侧
p
-s的结果合并为一个结果

由于语法中似乎没有分隔符,因此可以将
chainl1
与只返回组合函数的
op
一起使用:

callExpr :: IParser Expr
callExpr = chainl1 primaryExpr (return CallExpr)
至于您的
callExpr
实现,我可以发现两个错误

首先,使用
return$callExpr'e
,但是
callExpr'e
已经是一个一元值,所以只要
callExpr'e
就可以了


其次,在
e(\e2->callExpr'(callExpr e e2))e2m
中,默认的
e
应该是一元的(否则我们如何将其绑定到
e'
?),所以它应该是
return e

你能解释一下为什么需要这个组合器吗?是什么让它比使用
many
然后折叠结果更好呢?我还在尝试学习解析的基础知识。它可能快一些,但我认为它主要是约定和意图交流。我认为parser combinators通常应类似于“纯”尽可能多地使用CFG表示法,并应尽量减少事后AST操作的数量。我们的代码读者应该能够清楚地看到语法,并且不会被操作细节过度拖累。左递归是我们必须偏离抽象表示法的一个点,因此我们尝试将其封装在
chainl
中。
callExpr :: IParser Expr
callExpr = chainl1 primaryExpr (return CallExpr)