include "List.aes" namespace Option = function is_none(o : option('a)) : bool = switch(o) None => true Some(_) => false function is_some(o : option('a)) : bool = switch(o) None => false Some(_) => true /** Catamorphism on `option`. Also known as inlined pattern matching. */ function match(n : 'b, s : 'a => 'b, o : option('a)) : 'b = switch(o) None => n Some(x) => s(x) /** Escape option providing default if `None` */ function default(def : 'a, o : option('a)) : 'a = match(def, (x) => x, o) /** Assume it is `Some` */ function force(o : option('a)) : 'a = switch(o) None => abort("Forced None value") Some(x) => x function on_elem(o : option('a), f : 'a => unit) : unit = match((), f, o) function map(f : 'a => 'b, o : option('a)) : option('b) = switch(o) None => None Some(x) => Some(f(x)) function map2(f : ('a, 'b) => 'c , o1 : option('a) , o2 : option('b) ) : option('c) = switch((o1, o2)) (Some(x1), Some(x2)) => Some(f(x1, x2)) _ => None function map3( f : ('a, 'b, 'c) => 'd , o1 : option('a) , o2 : option('b) , o3 : option('c) ) : option('d) = switch((o1, o2, o3)) (Some(x1), Some(x2), Some(x3)) => Some(f(x1, x2, x3)) _ => None /** Like `map`, but the function is in `option` */ function app_over(f : option ('a => 'b), o : option('a)) : option('b) = switch((f, o)) (Some(ff), Some(xx)) => Some(ff(xx)) _ => None /** Monadic bind */ function flat_map(f : 'a => option('b), o : option('a)) : option('b) = switch(o) None => None Some(x) => f(x) function to_list(o : option('a)) : list('a) = switch(o) None => [] Some(x) => [x] /** Turns list of options into a list of elements that are under `Some`s. * Safe. */ function filter_options(l : list(option('a))) : list('a) = filter_options_(l, []) private function filter_options_(l : list (option('a)), acc : list('a)) : list('a) = switch(l) [] => List.reverse(acc) None::t => filter_options_(t, acc) Some(x)::t => filter_options_(t, x::acc) /** Just like `filter_options` but requires all elements to be `Some` and returns * None if any of them is not */ function seq_options(l : list (option('a))) : option (list('a)) = seq_options_(l, []) private function seq_options_(l : list (option('a)), acc : list('a)) : option(list('a)) = switch(l) [] => Some(List.reverse(acc)) None::t => None Some(x)::t => seq_options_(t, x::acc) /** Choose `Some` out of two if possible */ function choose(o1 : option('a), o2 : option('a)) : option('a) = if(is_some(o1)) o1 else o2 /** Choose `Some` from list of options if possible */ function choose_first(l : list(option('a))) : option('a) = switch(l) [] => None None::t => choose_first(t) Some(x)::_ => Some(x)