B. Ford の修士論文に従って、OCaml で packrat パーサーを実装しています。 私のパーサーは、言語の文法を表すデータ構造を受け取り、指定された一連の記号を解析する必要があります。
私はメモ化の部分で立ち往生しています。元の論文では、線形時間の複雑さを達成するために Haskell の遅延評価を使用しています。OCaml でこれ (遅延によるメモ化) を実行したいのですが、方法がわかりません。
では、OCaml で遅延評価によって関数をメモ化するにはどうすればよいでしょうか?
編集: 遅延評価とは何か、OCaml でそれを利用する方法を知っています。問題は、それを使って関数をメモ化する方法です。
編集:文法を表す私が書いたデータ構造は次のとおりです。
type ('a, 'b, 'c) expr =
| Empty of 'c
| Term of 'a * ('a -> 'c)
| NTerm of 'b
| Juxta of ('a, 'b, 'c) expr * ('a, 'b, 'c) expr * ('c -> 'c -> 'c)
| Alter of ('a, 'b, 'c) expr * ('a, 'b, 'c) expr
| Pred of ('a, 'b, 'c) expr * 'c
| NPred of ('a, 'b, 'c) expr * 'c
type ('a, 'b, 'c) grammar = ('a * ('a, 'b, 'c) expr) list
シンボルのリストを解析する (メモ化されていない) 関数は次のとおりです。
let rec parse g v xs = parse' g (List.assoc v g) xs
and parse' g e xs =
match e with
| Empty y -> Parsed (y, xs)
| Term (x, f) ->
begin
match xs with
| x' :: xs when x = x' -> Parsed (f x, xs)
| _ -> NoParse
end
| NTerm v' -> parse g v' xs
| Juxta (e1, e2, f) ->
begin
match parse' g e1 xs with
| Parsed (y, xs) ->
begin
match parse' g e2 xs with
| Parsed (y', xs) -> Parsed (f y y', xs)
| p -> p
end
| p -> p
end
( and so on )
parse の戻り値の型は、
type ('a, 'c) result = Parsed of 'c * ('a list) | NoParse
たとえば、基本的な算術式の文法は、次のように指定できますg
。
type nt = Add | Mult | Prim | Dec | Expr
let zero _ = 0
let g =
[(Expr, Juxta (NTerm Add, Term ('$', zero), fun x _ -> x));
(Add, Alter (Juxta (NTerm Mult, Juxta (Term ('+', zero), NTerm Add, fun _ x -> x), (+)), NTerm Mult));
(Mult, Alter (Juxta (NTerm Prim, Juxta (Term ('*', zero), NTerm Mult, fun _ x -> x), ( * )), NTerm Prim));
(Prim, Alter (Juxta (Term ('<', zero), Juxta (NTerm Dec, Term ('>', zero), fun x _ -> x), fun _ x -> x), NTerm Dec));
(Dec, List.fold_left (fun acc d -> Alter (Term (d, (fun c -> int_of_char c - 48)), acc)) (Term ('0', zero)) ['1';'2';'3';])]