Shells in OCaml
at main 72 lines 1.9 kB view raw
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 ignore = function 21 | Zero _ -> Zero () 22 | Nonzero v -> Nonzero { v with value = () } 23 24let value = function Zero v -> v | Nonzero { value; _ } -> value 25 26let not = function 27 | Zero value -> 28 Nonzero 29 { 30 value; 31 exit_code = 1; 32 message = None; 33 should_exit = default_should_exit; 34 } 35 | Nonzero { value; _ } -> Zero value 36 37let zero v = Zero v 38 39let nonzero ?message ?(should_exit = default_should_exit) value exit_code = 40 Nonzero { value; exit_code; message; should_exit } 41 42let code = function Zero _ -> 0 | Nonzero { exit_code; _ } -> exit_code 43 44let nonzero_msg ?(exit_code = 1) ?(should_exit = default_should_exit) value fmt 45 = 46 Fmt.kstr 47 (fun message -> 48 Nonzero { value; exit_code; message = Some message; should_exit }) 49 fmt 50 51let map ~f = function 52 | Zero v -> Zero (f v) 53 | Nonzero ({ value; _ } as v) -> Nonzero { v with value = f value } 54 55let map_zero ~f = function Zero v -> f v | Nonzero x -> Nonzero x 56 57let map' ~zero ~nonzero = function 58 | Zero v -> Zero (zero v) 59 | Nonzero v -> Nonzero { v with value = nonzero v.value } 60 61let is_nonzero = function Zero _ -> false | Nonzero _ -> true 62let is_zero = function Zero _ -> true | Nonzero _ -> false 63 64let pp ppf = function 65 | Zero _ -> Fmt.string ppf "zero" 66 | Nonzero _ -> Fmt.string ppf "nonzero" 67 68module Syntax = struct 69 let ( >|= ) x f = map ~f x 70 let ( >>= ) x f = map_zero ~f x 71 let ( let+ ) = ( >|= ) 72end