Shells in OCaml
1(* The shell exit applicative? This is very like the result monad,
2 except modelled around a shell's exit status codes *)
3
4type should_exit = {
5 interactive : [ `Yes | `No ];
6 non_interactive : [ `Yes | `No ];
7}
8
9let default_should_exit = { interactive = `No; non_interactive = `Yes }
10
11type 'a t =
12 | Zero of 'a
13 | Nonzero of {
14 value : 'a;
15 exit_code : int;
16 message : string option;
17 should_exit : should_exit;
18 }
19
20let value = function Zero v -> v | Nonzero { value; _ } -> value
21
22let not = function
23 | Zero value ->
24 Nonzero
25 {
26 value;
27 exit_code = 1;
28 message = None;
29 should_exit = default_should_exit;
30 }
31 | Nonzero { value; _ } -> Zero value
32
33let zero v = Zero v
34
35let nonzero ?message ?(should_exit = default_should_exit) value exit_code =
36 Nonzero { value; exit_code; message; should_exit }
37
38let nonzero_msg ?(exit_code = 1) ?(should_exit = default_should_exit) value fmt
39 =
40 Fmt.kstr
41 (fun message ->
42 Nonzero { value; exit_code; message = Some message; should_exit })
43 fmt
44
45let map ~f = function
46 | Zero v -> Zero (f v)
47 | Nonzero ({ value; _ } as v) -> Nonzero { v with value = f value }
48
49let map' ~zero ~nonzero = function
50 | Zero v -> Zero (zero v)
51 | Nonzero v -> Nonzero { v with value = nonzero v.value }
52
53let is_nonzero = function Zero _ -> false | Nonzero _ -> true
54let is_zero = function Zero _ -> true | Nonzero _ -> false
55
56let pp ppf = function
57 | Zero _ -> Fmt.string ppf "zero"
58 | Nonzero _ -> Fmt.string ppf "nonzero"
59
60module Syntax = struct
61 let ( >|= ) x f = map ~f x
62 let ( let+ ) = ( >|= )
63end