diff --git a/README.md b/README.md index 35b05db8..cfe96e5d 100644 --- a/README.md +++ b/README.md @@ -546,7 +546,7 @@ Some structural types are used throughout the library: ### Extended Documentation -See [the extended documentation](doc/containers.adoc) for more examples. +See [the extended documentation](doc/containers.md) for more examples. diff --git a/doc/containers.adoc b/doc/containers.md similarity index 63% rename from doc/containers.adoc rename to doc/containers.md index e6c564c6..d96f7683 100644 --- a/doc/containers.adoc +++ b/doc/containers.md @@ -1,12 +1,12 @@ -= OCaml-containers = -:toc: macro -:source-highlighter: pygments +# More about OCaml-containers This document contains more information on some modules of Containers. -toc::[] +```ocaml +# #require "containers";; +``` -== Hash combinators: `CCHash` +## Hash combinators: `CCHash` Although OCaml provides polymorphic hash tables (`('a,'b) Hashtbl.t`) using the polymorphic equality `(=)` and hash `Hashtbl.hash`, it is often @@ -15,63 +15,67 @@ with custom equality and hash functions. `CCHash` provides combinators for writing hash functions: -[source,OCaml] ----- +```ocaml # module H = CCHash;; +module H = CCHash # let hash1 : (int * bool) list H.t = H.(list (pair int bool));; +val hash1 : (int * bool) list H.t = +``` +```ocaml non-deterministic=output # hash1 [1, true; 2, false; 3, true];; - : int = 636041136 - -(* the function hashes the whole value, can be costly *) # hash1 CCList.(1 -- 1000 |> map (fun i->i, i mod 2 = 0));; - : int = 845685523 # hash1 CCList.(1 -- 1001 |> map (fun i->i, i mod 2 = 0));; - : int = 381026697 ----- +``` The polymorphic hash function is still present, as `CCHash.poly`. The functions `CCHash.list_comm` and `CCHash.array_comm` allow to hash lists and arrays while ignoring the order of elements: all permutations of the input will have the same hash. - - -== Parser Combinator: `CCParse` -:toc: macro -:source-highlighter: pygments +## Parser Combinator: `CCParse` The module `CCParse` defines basic parser combinators on strings. -Adapting https://github.com/inhabitedtype/angstrom#usage[angstrom's tutorial example] gives the following snippet. +Adapting [angstrom's tutorial example](https://github.com/inhabitedtype/angstrom#usage) +gives the following snippet. Note that backtracking is explicit in `CCParse`, hence the use of `try_` to allow it in some places. Explicit memoization with `memo` and `fix_memo` is also possible. -[source,OCaml] ----- -open CCParse.Infix;; -module P = CCParse;; +```ocaml +open CCParse.Infix +module P = CCParse -let parens p = P.try_ (P.char '(') *> p <* P.char ')' ;; -let add = P.char '+' *> P.return (+) ;; -let sub = P.char '-' *> P.return (-) ;; -let mul = P.char '*' *> P.return ( * ) ;; -let div = P.char '/' *> P.return ( / ) ;; +let parens p = P.try_ (P.char '(') *> p <* P.char ')' +let add = P.char '+' *> P.return (+) +let sub = P.char '-' *> P.return (-) +let mul = P.char '*' *> P.return ( * ) +let div = P.char '/' *> P.return ( / ) let integer = - P.chars1_if (function '0'..'9'->true|_->false) >|= int_of_string ;; + P.chars1_if (function '0'..'9'->true|_->false) >|= int_of_string let chainl1 e op = P.fix (fun r -> - e >>= fun x -> P.try_ (op <*> P.return x <*> r) <|> P.return x) ;; + e >>= fun x -> P.try_ (op <*> P.return x <*> r) <|> P.return x) let expr : int P.t = P.fix (fun expr -> let factor = parens expr <|> integer in let term = chainl1 factor (mul <|> div) in - chainl1 term (add <|> sub)) ;; + chainl1 term (add <|> sub)) +``` -P.parse_string expr "4*1+2";; (* Ok 6 *) -P.parse_string expr "4*(1+2)";; (* Ok 12 *) +Now we can parse strings using `expr`: + +```ocaml +# P.parse_string expr "4*1+2";; (* Ok 6 *) +- : int P.or_error = Result.Ok 6 + +# P.parse_string expr "4*(1+2)";; (* Ok 12 *) +- : int P.or_error = Result.Ok 12 +``` ----- diff --git a/doc/dune b/doc/dune new file mode 100644 index 00000000..54a2b6f7 --- /dev/null +++ b/doc/dune @@ -0,0 +1,8 @@ + +(alias + (name runtest) + (deps containers.md) + (action (progn + (run mdx test %{deps}) + (diff? %{deps} %{deps}.corrected)))) +