This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
212
unikernel/duniverse/base/README.org
Normal file
212
unikernel/duniverse/base/README.org
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
* Base
|
||||
|
||||
[[https://github.com/janestreet/base/actions][https://github.com/janestreet/base/actions/workflows/workflow.yml/badge.svg]]
|
||||
|
||||
Base is a standard library for OCaml. It provides a standard set of
|
||||
general purpose modules that are well-tested, performant, and
|
||||
fully-portable across any environment that can run OCaml code. Unlike
|
||||
other standard library projects, Base is meant to be used as a
|
||||
wholesale replacement of the standard library distributed with the
|
||||
OCaml compiler. In particular it makes different choices and doesn't
|
||||
re-export features that are not fully portable such as I/O, which are
|
||||
left to other libraries.
|
||||
|
||||
You also might want to browse the [[https://ocaml.janestreet.com/ocaml-core/latest/doc/base/index.html][API Documentation]].
|
||||
|
||||
** Installation
|
||||
|
||||
Install Base via [[https://opam.ocaml.org][OPAM]]:
|
||||
|
||||
#+begin_src
|
||||
$ opam install base
|
||||
#+end_src
|
||||
|
||||
Base has no runtime dependencies and is fast to build. Its sole build
|
||||
dependencies are [[https://github.com/ocaml/dune][dune]], which itself requires nothing more than the
|
||||
compiler, and [[https://github.com/janestreet/sexplib0][sexplib0]].
|
||||
|
||||
** Using the OCaml standard library with Base
|
||||
|
||||
Base is intended as a full stdlib replacement. As a result, after an
|
||||
=open Base=, all the modules, values, types, ... coming from the OCaml
|
||||
standard library that one normally gets in the default environment are
|
||||
deprecated.
|
||||
|
||||
In order to access these values, one must use the =Stdlib= library,
|
||||
which re-exports them all through the toplevel name =Stdlib=:
|
||||
=Stdlib.String=, =Stdlib.print_string=, ...
|
||||
|
||||
** Differences between Base and the OCaml standard library
|
||||
|
||||
Programmers who are used to the OCaml standard library should read
|
||||
through this section to understand major differences between the two
|
||||
libraries that one should be aware of when switching to Base.
|
||||
|
||||
*** Comparison operators
|
||||
|
||||
The comparison operators exposed by the OCaml standard library are
|
||||
polymorphic:
|
||||
|
||||
#+begin_src ocaml
|
||||
val compare : 'a -> 'a -> int
|
||||
val ( <= ) : 'a -> 'a -> bool
|
||||
...
|
||||
#+end_src
|
||||
|
||||
What they implement is structural comparison of the runtime
|
||||
representation of values. Since these are often error-prone,
|
||||
i.e. they don't correspond to what the user expects, they are not
|
||||
exposed directly by Base.
|
||||
|
||||
To use polymorphic comparison with Base, one should use the =Poly=
|
||||
module. The default comparison operators exposed by Base are the
|
||||
integer ones, just like the default arithmetic operators are the
|
||||
integer ones.
|
||||
|
||||
The recommended way to compare arbitrary complex data structures is to
|
||||
use the specific =compare= functions. For instance:
|
||||
|
||||
#+begin_src ocaml
|
||||
List.compare String.compare x y
|
||||
#+end_src
|
||||
|
||||
The [[https://github.com/janestreet/ppx_compare][ppx_compare]] rewriter
|
||||
offers an alternative way to write this:
|
||||
|
||||
#+begin_src ocaml
|
||||
[%compare: string list] x y
|
||||
#+end_src
|
||||
|
||||
** Base and ppx code generators
|
||||
|
||||
Base uses a few ppx code generators to implement:
|
||||
|
||||
- Reliable and customizable comparison of OCaml values.
|
||||
- Reliable and customizable hash of OCaml values.
|
||||
- Conversions between OCaml values and s-expression.
|
||||
|
||||
However, it doesn't need these code generators to build. What it does
|
||||
instead is use ppx as a code verification tool during development. It
|
||||
works in a very similar fashion to
|
||||
[[https://github.com/janestreet/ppx_expect][expectation tests]].
|
||||
|
||||
Whenever you see this in the code source:
|
||||
|
||||
#+begin_src ocaml
|
||||
type t = ... [@@deriving_inline sexp_of]
|
||||
let sexp_of_t = ...
|
||||
[@@@end]
|
||||
#+end_src
|
||||
|
||||
the code between the =[@@deriving_inline]= and the =[@@@end]= is
|
||||
generated code. The generated code is currently quite big and hard to
|
||||
read, however we are working on making it look like human-written
|
||||
code.
|
||||
|
||||
You can put the following elisp code in your =~/.emacs= file to hide
|
||||
these blocks:
|
||||
|
||||
#+begin_src scheme
|
||||
(defun deriving-inline-forward-sexp (&optional arg)
|
||||
(search-forward-regexp "\\[@@@end\\]") nil nil arg)
|
||||
|
||||
(defun setup-hide-deriving-inline ()
|
||||
(inline)
|
||||
(hs-minor-mode t)
|
||||
(let ((hs-hide-comments-when-hiding-all nil))
|
||||
(hs-hide-all)))
|
||||
|
||||
(require 'hideshow)
|
||||
(add-to-list 'hs-special-modes-alist
|
||||
'(tuareg-mode "\\[@@deriving_inline[^]]*\\]" "\\[@@@end\\]" nil
|
||||
deriving-inline-forward-sexp nil))
|
||||
(add-hook 'tuareg-mode-hook 'setup-hide-deriving-inline)
|
||||
#+end_src
|
||||
|
||||
Things are not yet setup in the git repository to make it convenient
|
||||
to change types and update the generated code, but they will be setup
|
||||
soon.
|
||||
|
||||
** Base coding rules
|
||||
|
||||
There are a few coding rules across the code base that are enforced by
|
||||
lint tools.
|
||||
|
||||
These rules are:
|
||||
|
||||
- Opening the =Stdlib= module is not allowed. Inside Base, the OCaml
|
||||
stdlib is shadowed and accessible through the =Stdlib= module. We
|
||||
forbid opening =Stdlib= so that we know exactly where things come
|
||||
from.
|
||||
- =Stdlib.Foo= modules cannot be aliased, one must use =Stdlib.Foo=
|
||||
explicitly. This is to avoid having to remember a list of aliases
|
||||
at the beginning of each file.
|
||||
- For some modules that are both in the OCaml stdlib and Base, such as
|
||||
=String=, we define a module =String0= for common functions that
|
||||
cannot be defined directly in =Base.String= to avoid creating a
|
||||
circular dependency. Except for =String= itself, other modules
|
||||
are not allowed to use =Stdlib.String= and must use either =String= or
|
||||
=String0= instead.
|
||||
- Indentation is exactly the one of =ocp-indent=.
|
||||
- A few other coding style rules enforced by
|
||||
[[https://github.com/janestreet/ppx_js_style][ppx_js_style]].
|
||||
|
||||
The Base specific coding rules are checked by =ppx_base_lint=, in the
|
||||
=lint= subfolder. The indentation rules are checked by a wrapper around
|
||||
=ocp-indent= and the coding style rules are checked by =ppx_js_style=.
|
||||
|
||||
These checks are currently not run by =dune=, but it will soon get a
|
||||
=-dev= flag to run them automatically.
|
||||
|
||||
** Sexp (de-)serializers
|
||||
|
||||
Most types in Base have ~sexp_of_t~ and ~t_of_sexp~ functions for converting
|
||||
between values of that type and their sexp representations.
|
||||
|
||||
One pair of functions deserves special attention: ~String.sexp_of_t~ and
|
||||
~String.t_of_sexp~. These functions have the same types as ~Sexp.of_string~ and
|
||||
~Sexp.to_string~ but very different behavior.
|
||||
|
||||
~String.sexp_of_t~ and ~String.t_of_sexp~ are used to encode and decode strings
|
||||
"embedded" in a sexp representation. On the other hand, ~Sexp.of_string~ and
|
||||
~Sexp.to_string~ are used to encode and decode the textual form of
|
||||
s-expressions.
|
||||
|
||||
The following example demonstrates the two pairs of functions in action:
|
||||
|
||||
#+begin_src ocaml
|
||||
open! Base
|
||||
open! Stdio
|
||||
|
||||
(* Embed a string in a sexp *)
|
||||
|
||||
let example_sexp : Sexp.t = List.sexp_of_t String.sexp_of_t [ "hello"; "world" ]
|
||||
|
||||
let () =
|
||||
assert (Sexp.equal example_sexp (Sexp.List [ Sexp.Atom "hello"; Sexp.Atom "world" ]))
|
||||
;;
|
||||
|
||||
let () =
|
||||
assert (
|
||||
List.equal
|
||||
String.equal
|
||||
[ "hello"; "world" ]
|
||||
(List.t_of_sexp String.t_of_sexp example_sexp))
|
||||
;;
|
||||
|
||||
(* Embed a sexp in text (string) *)
|
||||
|
||||
let write_sexp_to_file sexp =
|
||||
Out_channel.write_all "/tmp/file" ~data:(Sexp.to_string example_sexp)
|
||||
;;
|
||||
|
||||
(* /tmp/file now contains:
|
||||
|
||||
{v
|
||||
(hello world)
|
||||
v} *)
|
||||
|
||||
let () =
|
||||
assert (Sexp.equal example_sexp (Sexp.of_string (In_channel.read_all "/tmp/file")))
|
||||
;;
|
||||
#+end_src
|
||||
Loading…
Add table
Add a link
Reference in a new issue