私の使っているライブラリ、FParsec
しかし扱いが難しい...
ならいっそのこと、作ってしまえ!
そんなわけで、パーサコンビネータPsictreを簡易ながらも作りました
誕生秘話①
今まで、私は以下のDSLを作りました
- ParserScript (ファイル消失)
- UCCScript (バグあり・可読性皆無・孤立したDSL)
- ChainCC / CC+ (孤立したDSL)
CC+にて開発言語のF#と連携させる試みがありましたが、できることがほぼありませんでした
今回のPsictreはF#用ライブラリとなっています。別のファイルに専用のスクリプトを書くことはしません
これで、F#の力を100%引き出すことができます
誕生秘話②
ある時、私はこう考えました
パースした後のASTを型推論でもう一度組み立て直すのは面倒くさい!
だったら、パースと同時に型推論をやってしまおうではないか
しかしながら、Psictreに型推論エンジンを持たせるのは難しいです
理由として以下があげられます
- 作る言語が動的型かもしれない
- オブジェクトの考え方が違うかもしれない
仮にPsictreをNugetパッケージとして公開したとしましょう
Psictreは私の言語のために作っているわけですから、フレーム指向専用にできています
それでは、オブジェクト指向言語は作れなくなってしまいます
そのため、Psictreでは型推論をアシストする機能を提供するだけにしました
書き味
PsictreはF#特有の「コンピューテーション式」を使います
type Fruits =
| Apple
| Orange
[<EntryPoint>]
let main =
let wspace = parse {
let! _ = pchar ' '
}
let appleOrOrange =
parse {
let! _ = pstring "apple")
return Apple
}
<|>
parse {
let! _ = pstirng "orange"
return Orange
}
let p = parse {
let! first, _ = appleOrOrange
let! list, _ = many (parse {
let! _ = wspace
let! res, _ = appleOrOrange
return res
})
return first :: list
}
let input = "orange apple apple orange apple"
let result = run p input
let countOfApples =
result
|> List.filter ((=) Apple)
|> List.length
let countOfOranges =
result
|> List.filter ((=) Orange)
|> List.length
printfn "apple=%i, orange=%i" countOfApples countOfOranges
// => "apple=3, orange=2"
0
終わりに
これから、型推論のアシスト機能追加に移ります