Упоминание списка в Ocaml?

Кажется, что батареи Ocaml имеют синтаксис понимания: http://en.wikipedia.org/wiki/List_comprehension#OCaml

Однако, какой модуль я должен использовать для использования этого синтаксиса? Я уже open Batteries, но он не работает. Или существует ли более идиоматический способ понимания списка? Я могу использовать List.map и BatList.remove_if для достижения аналогичных результатов, но это намного менее изящно.

Ответ 1

В настоящее время в 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))

Следовательно, a 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))

Вы можете заметить, что эти примеры содержат больше кода, чем понимание списка. Но как только ваши программы начнут зрелы от простых мировых приложений с целыми числами до чего-то более сложного, вы согласитесь, что использование явных итераторов более читабельно и понятно.

Кроме того, поскольку библиотеки в Core настолько согласованы, вы можете использовать простой List вместо Sequence, просто заменив последний на первый. Но, конечно, List нетерпелив, в отличие от Sequence, поэтому играть с max_int с помощью списков не очень хорошая идея.

Кроме того, поскольку все контейнеры являются монадами, вы можете использовать монадические операторы для отображения, например:

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

Ответ 2

понимание списка уже включено в стандартный ocaml

#require "camlp4.listcomprehension";;

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

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