FParsec を使用して標準の単純型 (ラムダ計算の意味で) を解析しようとしていますが、特に再帰的な定義に関して、Lex/Yacc スタイルから FParsec で使用されるスタイルに移行するのに苦労しています。
私が解析しようとしている型の例は次のとおりです。
- o
- o -> o
- (o -> o -> o) -> o
そして、ここに私の試みがあります:
type SType =
| Atom
| Arrow of SType * SType
let ws = spaces
let stype, styperef = createParserForwardedToRef()
let atom = pchar 'o' .>> ws |>> (fun _ -> Atom)
let arrow = pipe2 (stype .>> (pstring "->" .>> ws))
stype
(fun t1 t2 -> Arrow (t1,t2))
let arr = parse {
let! t1 = stype
do! ws
let! _ = pstring "->"
let! t2 = stype
do! ws
return Arrow (t1,t2)
}
styperef := choice [ pchar '(' >>. stype .>> pchar ')';
arr;
atom ]
let _ = run stype "o -> o"`
これをインタラクティブにロードすると、最後の行でスタック オーバーフローが発生します (皮肉なことに、最近では検索が非常に困難です)。再帰参照があることを考えると、その理由は想像できますが、1 つのトークンの先読みでは、stype
. したがって、それは を選択しているに違いないと思いarr
ますstype
。しかし、このループを防ぐにはどうすればよいでしょうか?
ライブラリの慣用的な使用に関するコメントと、試みた解決策の修正に興味があります。