问题
I have written a function to deoptionalize an integer list and I would like to know if there is a better way to write it.
let deoptionalize (lst:'a option list) : 'a list =
List.map ~f:(fun x -> match x with Some x -> x | None -> assert false)
(List.filter ~f:(fun x -> x <> None) lst)
;;
In the assignment I am currently working its using map and filter is a must.
回答1:
I suppose that a "hand-coded" solution (i.e. without map and filter) is easier to read, but if you really need to use them, here you go:
It seems that you are using the Core library. If so, I think your solution is not so bad, but can be written a bit more compact:
let deoptionalize lst =
List.filter ~f:(is_some) lst
|> List.map ~f:(function | Some x -> x | None -> assert false)
If you don't mind warnings (which I discourage you to do), you can even leave out some more:
let deoptionalize lst =
List.filter ~f:(is_some) lst
|> List.map ~f:(fun (Some x) -> x)
Actually, Core provides filter_map (thanks @Ramon Snir for the hint) which combines both, so you can use:
let deopt lst =
List.filter_map ~f:(fun x -> x) lst;;
回答2:
In your case, I prefer doing in this way:
let deoptionalize l =
let rec deopt acc = function
| [] -> List.rev acc
| None::tl -> deopt acc tl
| Some x::tl -> deopt (x::acc) tl
in
deopt [] l
It is more clear and tail-recursive and performance is better
回答3:
Another solution,
let deoptionalize l =
List.concat @@ List.map (function | None -> [] | Some x -> [x]) l
来源:https://stackoverflow.com/questions/21674947/ocaml-deoptionalize-a-list-is-there-a-simpler-way