列表中的Ocaml理解?

时间:2014-12-26 03:01:45

标签: ocaml

似乎Ocaml电池具有理解语法: http://en.wikipedia.org/wiki/List_comprehension#OCaml

但是,我应该包含哪个模块才能使用此语法?我已经open Batteries,但它不起作用。或者是否有一种更惯用的方式来做列表理解?我可以使用List.map和BatList.remove_if来实现类似的结果,但这不太优雅。

2 个答案:

答案 0 :(得分:12)

目前,OCaml中有两个提供列表理解的库,一个以前是OCaml Batteries的一部分,另一个是随camlp4一起提供的。两者都没有被广泛使用,我个人不建议您使用任何。

要使列表理解起作用,您需要更改语言的语法。这可以通过使用camlp4预处理器以扩展语法编写的程序预处理来完成。此外,列表理解不是OCaml社区中的一等公民,现代工具包也不能很好地支持它。虽然,您仍然可以轻松地在顶层玩它,为您所需要的,安装列表理解包:

opam install pa_comprehension 

并使用以下指令将其加载到顶层:

# #use "topfind";;
# #camlp4o;;
# #require "pa_comprehension";;
# open Batteries;;
# [? 2 * x | x <- 0 -- max_int ; x * x > 3 ?];;

但是,我个人认为列表理解并不是构建代码的最佳方式。

没有理解的生活

您提供的示例可以使用core_kernel Sequence模块(电池类似Enum)表示

let f n =
  Sequence.(range 0 n |>
            filter ~f:(fun x -> x * x > 3) |>
            map ~f:(fun x -> x * 2))

因此,filter |> map是一种常见的习惯用法,存在filter_map函数:

let f n =
  Sequence.(range 0 n |>
            filter_map ~f:(fun x ->
                if x * x > 3 then Some (x * 2) else None))

你可能会注意到,这个例子比列表理解需要更多的代码。但是一旦你的程序开始从简单的整数hello world应用程序成熟到更复杂的东西,你就会同意使用显式迭代器更具可读性和可理解性。

此外,由于Core中的库非常一致,您可以使用简单的List代替Sequence,只需用前者替换后者即可。但当然,与List不同,Sequence非常渴望,所以使用列表与max_int一起玩并不是一个好主意。

此外,由于所有容器都是monad,因此可以使用monadic运算符进行映射,例如:

let odds n = List.(range 0 n >>| fun x -> x * 2 + 1)

答案 1 :(得分:1)

列表理解已包含在标准ocaml

#require "camlp4.listcomprehension";;

[ x * x | x <- [ 1;2;3;4;5] ];;

- : int list = [1; 4; 9; 16; 25]