【问题标题】:List Comprehension in Ocaml?Ocaml中的列表理解?
【发布时间】:2015-02-23 11:43:11
【问题描述】:

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

但是,我应该包含什么模块才能使用这种语法?我已经open Batteries,但它不起作用。还是有更惯用的方法来进行列表理解?我可以使用 List.map 和 BatList.remove_if 来实现类似的结果,但这样就不太优雅了。

【问题讨论】:

    标签: ocaml


    【解决方案1】:

    列表推导已经包含在标准 ocaml 中

    #require "camlp4.listcomprehension";;
    
    [ x * x | x <- [ 1;2;3;4;5] ];;
    
    - : int list = [1; 4; 9; 16; 25]
    

    【讨论】:

    • 现在已经不是这样了。
    【解决方案2】:

    目前 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 |&gt; 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)
    

    【讨论】:

    • 那么你会推荐什么呢?
    • 例如,如果我想得到类似(在 python 代码中)[x*2 for x in xlist if x>3] 之类的东西,有没有一种干净的方法可以做到这一点?
    • @user69818:将List.filter 用于&gt;3 条件,然后使用List.map
    • @user69818:如果你定义了一个管道操作符|&gt;,那就没那么糟糕了(参见ocamlpro.com/blog/2012/08/20/ocamlpro-and-4.00.0.html“管道操作符”)
    • 最后一个表达式与python中的[ x * 2 + 1 for x in range(n) ]相同。 Monad 可以看作是容器的泛化,实际上 monadic map 操作符与任何其他容器的 map 操作符完全相同。这是一个很好的tutorial
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 2019-02-16
    • 1970-01-01
    相关资源
    最近更新 更多