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

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

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

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_kernelSequence модуль (аналог Батареи 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 использование списков не очень хорошая идея.

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

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

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

#require "camlp4.listcomprehension";;

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

- : int list = [1; 4; 9; 16; 25]
Другие вопросы по тегам