4

次の文法生成を変換しようとしています

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;
                   .... }

このタイプのエラーを修正するにはどうすればよいですか?

4

1 に答える 1

5

を使用しchainl1ます。-s で区切られたchainl1 p op1 つ以上の-sを左結合で解析します。両側の -s の結果を単一の結果に結合するために使用される二項関数を返します。popopp

あなたの文法にはセパレーターがないように見えるので、結合関数を返すだけchainl1のを使用できます。op

callExpr :: IParser Expr
callExpr = chainl1 primaryExpr (return CallExpr)

あなたのcallExpr実装に関しては、2 つのエラーを見つけることができます。

まず、 を使用しますreturn $ callExpr' eが、callExpr' eすでにモナド値であるため、callExpr' e正しいでしょう。

次に、maybe e (\e2 -> callExpr' (CallExpr e e2)) e2mでは、デフォルトeはモナドでなければなりません (そうでなければ、どのようにバインドできますe'か?) return e

于 2015-03-25T14:36:46.490 に答える