Let’s do a bit of type puzzle. find_map has type :
('a -> 'b option) -> 'a list -> 'b
This version raises an exception if the first argument f returns None for every element in the iterated list. If we want to stay pure, we could give find_map the type :
('a -> 'b option) -> 'a list -> 'b option
This one is a total function, it just returns None if f has returned None for all elements of l.
Then Option.map has type :
('a -> 'b) -> 'a option -> 'b option
and find_opt has type :
('a -> bool) -> 'a list -> 'a option
By working out the types, you see you can get a function with a type quite similar to find_map by composing find_opt and map this way :
let mystery predicate f l =
List.find_opt predicate l
|> Option.map f
type mystery = ('a -> bool) -> ('a -> 'b) -> 'a list -> 'b option
This function just selects an element returning true for predicate, then applies f to it if it finds one.
Actually find_map just allows you to select and transform your element on the fly.
So this same mystery function could be expressed this way :
let mystery p f l = List.find_map (fun x -> if p x then Some (f x) else None) l