私はちょっとモナドなパーサーコンビネータライブラリをF#(やや似ているのはFParsec)で書いていて、プログラミング言語用の小さなパーサを実装しようとしました。解析:F#で遅延初期化と相互再帰的なモナド
私は最初、完全にうまく走ったHaskell(Parsec)でコードを実装しました。 中置式のパーサは、相互に再帰的に設計されています。
parseInfixOp :: Parser String -> Parser Expression -> Parser Expression
parseInfixOp operatorParser subParser = ignoreSpaces $ do
x <- ignoreSpaces $ subParser
do
op <- ignoreSpaces $ operatorParser
y <- parseInfixOp operatorParser subParser
return $ BinaryOp op x y
<|> return x
parseInfix :: [String] -> Parser Expression -> Parser Expression
parseInfix list = parseInfixOp (foldl1 (<|>) $ map string list)
parseExpr :: Parser Expression
parseExpr = parseInfix0
parseInfix0 = parseInfix ["==", "<>", "And", "Or", "Xor", "<", ">", "<=", ">="] parseInfix1
parseInfix1 = parseInfix ["+", "-", "Mod"] parseInfix2
parseInfix2 = parseInfix ["*", "/", "\\"] parseInfix3
parseInfix3 = parseInfix ["^"] parseInfix4
parseInfix4 = parseFactor
parseFactor :: Parser Expression
parseFactor = parseFactor' <|> (betweenChars '(' ')' parseExpr)
parseFactor' :: Parser Expression
parseFactor' = parseString
<|> parseBool
<|> parseNumber
<|> parseVariable
<|> (try parseFunCall) <|> parseIdentifier
機能の順序は重要ではないとHaskellは非厳密な方法で評価されているので、これはOKですが、F#が厳密に評価しています。
let rec parseExpr = parseInfix0
and parseFactor = (parseFactor') <|> (betweenChars '(' ')' parseExpr)
and parseInfix2 = parseInfix ["^"] parseFactor BinaryOp
and parseInfix1 = parseInfix ["*"; "/"] parseInfix2 BinaryOp
and parseInfix0 = parseInfix ["+"; "-"] parseInfix1 BinaryOp
and parseFunCall = parser {
let! first = letter
let! rest = many (letter <|> digit)
let funcName = toStr $ first::rest
do! ignoreSpace
let! args = betweenChars '(' ')' $ sepBy (parseExpr) ","
return FunCall(funcName, args)
}
and parseFactor' =
parseNumber
<|> parseString
<|> parseBool
<|> parseFunCall
<|> parseIdentifier
F#では、再帰的なオブジェクト文句どちらかとばかりによる無限ループに、実行時にStackOverflowException
を投げるか「値は、独自のdefinionの一部となる」ので、それもソースをコンパイルしません。
このエラーを防ぐ最も良い方法は何ですか。デバッガは私に代わりに関数またはlazy
を使用するようにアドバイスしますが、ここで何を怠けばよいでしょうか?
パーフェクト - 明示的なη変換が私のソリューションでした!お返事ありがとうございます。 – Dario