package parseff
Install
dune-project
Dependency
Authors
Maintainers
Sources
sha256=a49fa685546f8d9bc90d59a62ecc8204a24621b438164503745024e1038ebc9b
sha512=43baed140dcce2fd6e024a1f03daa71a923b1de19efa41c73eced3550528d5d911b8f0fc13dbb795f7af7a6fc963fc9d0a5fa8a9099ca752696e90345514f6ac
Description
Parseff is a direct-style parser combinator library for OCaml 5 where parsers are plain functions (unit -> 'a), errors are typed via polymorphic variants, and algebraic effects handle control flow, backtracking, and streaming input. Designed for performance with zero-copy span APIs and fused operations.
Published: 23 Mar 2026
README
Parseff
Parseff is a direct-style parser combinator library for OCaml 5 where parsers are plain functions (unit -> 'a), errors are typed via polymorphic variants, and algebraic effects handle control flow, backtracking, and streaming input. Designed for performance with zero-copy span APIs and fused operations.
Installation
$ opam install parseff -yExample
let number () =
let digits = Parseff.many ~at_least:1 Parseff.digit () in
let n = List.fold_left (fun acc d -> (acc * 10) + d) 0 digits in
if n >= 0 && n <= 255 then n
else Parseff.error (`Out_of_range n)
let ip_address () =
let a = number () in
let _ = Parseff.char '.' in
let b = number () in
let _ = Parseff.char '.' in
let c = number () in
let _ = Parseff.char '.' in
let d = number () in
Parseff.end_of_input ();
(a, b, c, d)
let () =
match Parseff.parse "192.168.1.1" ip_address with
| Ok ((a, b, c, d)) ->
Printf.printf "Parsed: %d.%d.%d.%d\n" a b c d
| Error { pos; error = `Out_of_range n } ->
Printf.printf "Error at %d: %d out of range (0-255)\n" pos n
| Error { pos; error = `Unexpected_end_of_input } ->
Printf.printf "Error at %d: unexpected end of input\n" pos
| Error { pos; error = `Expected msg } ->
Printf.printf "Error at %d: %s\n" pos msg
| Error { pos; error = `Depth_limit_exceeded msg } ->
Printf.printf "Error at %d: %s\n" pos msgFeatures
- Build parsers with direct-style and compose with
Parseffcombinators - API is designed to be expressive enough to not need monadic operators (
>>=,>>|,*>), nor binding operators (let*,let+,and+) - Typed domain errors via polymorphic variants, raise with
Parseff.error. Parseff also addsExpected of string`,Unexpected_end_of_input, and ``Depth_limit_exceeded of stringas possible parsing failures - Automatic backtracking with
Parseff.or_ - Minimal dependency footprint: only
refor regex support - Streaming support with
Source.of_string,Source.of_channel,Source.of_function - Domain-safe: each
Parseff.parse/Parseff.parse_sourcecall is self-contained with no global mutable state, so independent parses can run in parallel across domains - Zero-copy span APIs for low-allocation parsing (
Parseff.take_while_span,Parseff.sep_by_take_span,Parseff.fused_sep_take,Parseff.skip_while_then_char) - Fused operations for hot paths (
Parseff.sep_by_take,Parseff.skip_while_then_char)
Performance
Parseff is faster than Angstrom and MParser by a factor of 2 to 4x. In case of equal implementations, Parseff is ~2x faster than Angstrom and MParser. With an optimized version using zero-copy span APIs, that gap widens to ~4x. See the full comparison for details and bench/bench_vs_angstrom.ml for the benchmark.
Documentation
- Quick start
- API overview
- Your first parser
- Error handling
- Making parsers fast
- Comparison with Angstrom
- A JSON parser
- Expressions with precedence
Contributing
- Open an issue to discuss proposed changes
- Write tests for new features
- Run
make fmtbefore submitting - Ensure all tests pass with
make test
License
MIT. See LICENSE for details.
Dev Dependencies (10)
-
mdx
with-test -
odoc-parser
with-doc -
odoc
>= "3.1.0" & with-doc -
ocaml-lsp-server
with-dev-setup -
ocamlformat
>= "0.29.0" & with-dev-setup -
mparser
with-test -
angstrom
with-test -
benchmark
with-test -
alcotest
with-test -
dune
>= "3.17" & (>= "3.22" & with-doc = "true" | with-doc = "false")
Used by
None
Conflicts
None