Понимание списка в 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_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
использование списков не очень хорошая идея.
Более того, поскольку все контейнеры являются монадами, вы можете использовать монадические операторы для отображения, например:
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]