Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List Comprehension in Ocaml?

Tags:

ocaml

It seems that Ocaml batteries have comprehension syntax: http://en.wikipedia.org/wiki/List_comprehension#OCaml

However, what module should I include to use this syntax? I already open Batteries, but it doesn't work. Or is there a more idiomatic way to do list comprehension? I can use List.map and BatList.remove_if to achieve similar results, but that is much less elegant.

like image 918
user69818 Avatar asked Dec 26 '14 03:12

user69818


2 Answers

Currently there're two libraries in OCaml that provide list comprehension, one was formerly a part of OCaml Batteries, another is shipped with camlp4. Neither is widely used and I, personally, do no recommend you to use any.

For list comprehension to work, you need to change the syntax of the language. This can be done with preprocessing your program, written in an extended syntax, with a camlp4 preprocessor. Also, list comprehension is not a first class citizen in OCaml community, and it is not well supported by the modern toolkits. Although, you can still easily play with it in a toplevel, for that you need, to install the list comprehension package:

opam install pa_comprehension 

and load it into a toplevel, using the following directives:

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

But again, my personal opinion that list comprehension is not the best way to structure your code.

Life without comprehension

The example, you provided, can be expressed using core_kernel Sequence module (an analog of the Batteries Enum)

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

Hence a filter |> map is such a common idiom there exists a filter_map function:

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

You may notice, that this examples takes more code, than list comprehension. But as soon as your programs will start to mature from simple hello world applications with integers to something more sophisticated, you will agree that using explicit iterators is more readable and comprehensible.

Also, since libraries in Core are so consistent, you can use a simple List instead of Sequence just by substituting the latter by the former. But of course, List is eager, unlike the Sequence, so playing with max_int using lists is not a good idea.

Moreover, since all containers are monads, you can use monadic operators for mapping, like:

let odds n = List.(range 0 n >>| fun x -> x * 2 + 1)
like image 85
ivg Avatar answered Nov 20 '22 03:11

ivg


list comprehension is already included in standard ocaml

#require "camlp4.listcomprehension";;

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

- : int list = [1; 4; 9; 16; 25]
like image 2
Marko Tunjic Avatar answered Nov 20 '22 02:11

Marko Tunjic