0

学習演習として、機能パーサーライブラリfparsec(FParsec )を使用してgraphvizドット言語( DOT言語)のパーサーを実装しようとしています。言語はグラフを記述します。

言語の定義を見て、私は次の定義を書き留めることを余儀なくされました。

let rec pstmt_list = opt(pstmt .>> opt(pchar ';') >>. opt pstmt_list)

ここpstmtで、およびpchar ';'はパーサーで.>>あり>>.、左側のパーサーの出現と右側のパーサーの出現を組み合わせ、optオプション値としてその引数パーサーのオプションの出現をパーサーします。ただし、この定義は「...結果の型は無限になります...」と文句を言っても機能しません。

この例は、上記のリンク先のDOT言語を見るとおそらく最も簡単に理解できます。

私は次の一見リンクされた質問を知っています:

しかし、私のF#の知識は、それらがここに当てはまるとしても、まだそれらを翻訳するには十分ではないかもしれません。

4

2 に答える 2

4

FParsec は、シーケンスを解析するための特別なコンビネータを提供します。通常、これらのコンビネータは、再帰関数で再実装するよりも優先する必要があります。シーケンスの解析に使用できるコンビネータの概要については、http ://www.quanttec.com/fparsec/reference/parser-overview.html#parsing-sequences を参照してください。

この例pstmt_listでは、一連のステートメントがセミコロンで区切られ、オプションで終了しているため、パーサーを次のように簡単に定義できます。

let pstmt_list = sepEndBy pstmt (pstring ";")
于 2011-06-21T19:29:56.173 に答える
2

問題は、pstmt_listパーサーが何らかの型のいくつかの値を生成することですが、それを定義で使用すると、この型の値が追加のoption型でラップされます (optコンビネーターを使用)。

F# コンパイラは、たとえばパーサーによって返される値の型は'a、ラップされた型と同じである必要があると考えますoption 'a(もちろん、これは不可能です)。

とにかく、これはあなたがする必要があることではないと思います -.>>コンビネーターは 2 番目の引数の結果を返すパーサーを作成します。つまり、pstmtこれまでの parsed のすべての結果を無視することになります。

おそらく次のようなものが必要だと思います:

let rec pstmt_list : Parser<int list, unit> = 
  parse.Delay(fun () ->
    opt(pstmt .>> pchar ';') .>>. opt pstmt_list
    |>> (function Some(prev), Some(rest) -> prev::rest
                | Some(prev), _ -> [prev]
                | _, Some(rest) -> rest
                | _ -> [] ))

の追加の使用法はDelay、それ自体を直接参照する値の宣言を避けることです。

于 2011-06-21T13:15:04.950 に答える