[英]Translate grammar production to Parsec
我正在嘗試轉換以下語法生成
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'
其中primaryExpr
類型為IParser Expr
,IParser的定義為
type IParser a = ParsecT String () (State SourcePos) a
但是這會給我以下類型錯誤:
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;
.... }
如何修復此類錯誤?
使用chainl1
。 chainl1 p op
以左關聯方式解析由op
-s分隔的一個或多個p
-s。 op
返回一個二元函數,用於將兩側的p
-s結果合並為一個結果。
由於你的語法似乎沒有分隔符,你可以使用帶有只返回組合函數的op
chainl1
:
callExpr :: IParser Expr
callExpr = chainl1 primaryExpr (return CallExpr)
至於你的callExpr
實現,我可以發現兩個錯誤。
首先,你使用return $ callExpr' e
,但callExpr' e
已經是一個callExpr' e
值,所以只需callExpr' e
就是正確的。
其次,在maybe e (\\e2 -> callExpr' (CallExpr e e2)) e2m
,默認的e
應該是maybe e (\\e2 -> callExpr' (CallExpr e e2)) e2m
(或者我們怎么能將它綁定到e'
?),所以應該return e
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.