Inspect.Algebra
Набор функций для создания и обработки документов алгебры.
Этот модуль реализует функциональность, описанную в «Strictly Pretty» (2000) Кристиана Линдига с небольшими дополнениями, такими как поддержка узлов String и настраиваемая функция визуализации, которая максимизирует использование горизонтального пространства.
iex> Inspect.Algebra.empty :doc_nil iex> "foo" "foo"
С помощью функций в этом модуле мы можем конкатенировать различные элементы вместе и визуализировать их:
iex> doc = Inspect.Algebra.concat(Inspect.Algebra.empty, "foo") iex> Inspect.Algebra.format(doc, 80) ["foo"]
Функции nest/2, space/2 и line/2 помогут вам собрать документ в строгую структуру. Однако алгебра документов становится интересной при использовании функций, таких как break/2, которая преобразует заданную строку в перевод строки в зависимости от того, сколько места есть для печати. Давайте склеим два документа вместе с разрывом и затем визуализируем их:
iex> doc = Inspect.Algebra.glue("a", " ", "b")
iex> Inspect.Algebra.format(doc, 80)
["a", " ", "b"] Обратите внимание, что разрыв был представлен как есть, потому что мы не достигли предела строки. Как только это произойдет, он заменится новой строкой:
iex> doc = Inspect.Algebra.glue(String.duplicate("a", 20), " ", "b")
iex> Inspect.Algebra.format(doc, 10)
["aaaaaaaaaaaaaaaaaaaa", "\n", "b"] Наконец, этот модуль также содержит связанные с Elixir функции, немного связанные с форматированием Elixir, а именно surround/3 и surround_many/5.
Подробности реализации
Исходная реализация алгоритма на Haskell автором Уэдлера полагается на ленивое вычисление для развертывания групп документов по двум альтернативам: :flat (разрывы как пробелы) и :break (разрывы как новые строки). Реализация того же логики на строгом языке, таком как Elixir, приводит к экспоненциальному росту возможных документов, если группы документов не закодированы явно как :flat или :break. Эти группы затем сводятся к простому документу, где макет уже определен, согласно Линдигу.
Эта реализация немного изменяет семантику алгоритма Линдига, чтобы позволить элементам, принадлежащим к одной группе, печататься вместе в одной строке, даже если они не помещаются полностью в строку. Это было достигнуто путем изменения :break для обозначения возможного разрыва и :flat для принудительной плоской структуры. Затем решение о том, работает ли разрыв как новая строка, сводится к проверке наличия достаточного места до следующего разрыва, который не находится внутри группы (которая все еще плоская).
Настраиваемые красивщики могут быть реализованы с помощью документов, возвращаемых этим модулем, и путем предоставления собственных функций визуализации.
Резюме
Типы
- t()
Функции
- break()
- break(s)
-
Сущность документа, представляющая разрыв
- concat(docs)
-
Конкатенирует список документов
- concat(x, y)
-
Конкатенирует две сущности документа
- empty()
-
Возвращает сущность документа, используемую для представления пустоты
- fold_doc(list, fun)
-
Складывает список сущностей документов в сущность документа с использованием функции, которая передается в качестве первого аргумента
- format(d, w)
-
Функция форматирования
- glue(x, y)
-
Вставляет разрыв между двумя документами. См.
break/1для получения дополнительной информации - glue(x, g, y)
-
Вставляет разрыв, переданный во втором аргументе, между двумя документами, первым и третьим аргументами
- group(d)
-
Возвращает группу, содержащую указанный документ
- line(x, y)
-
Вставляет обязательный перевод строки между двумя сущностями документа
- nest(x, i)
-
Вкладывает сущность документа
xпозиций глубоко - space(x, y)
-
Вставляет обязательный одиночный пробел между двумя сущностями документа
- surround(left, doc, right)
-
Оборачивает документ символами
- surround_many(left, docs, right, opts, fun, separator \\ ",")
-
Картирует и склеивает коллекцию элементов
- to_doc(map, opts)
-
Преобразует структуру Elixir в документ алгебры в соответствии с протоколом inspect
Типы
t()
t :: :doc_nil | :doc_line | doc_cons | doc_nest | doc_break | doc_group | binary
Функции
break()
break() :: doc_break
break(s)
break(binary) :: doc_break
Сущность документа, представляющая разрыв.
Этот разрыв может быть визуализирован как перевод строки или как пробелы, в зависимости от mode выбранного макета или предоставленного разделителя.
Примеры
Давайте склеим два документа вместе с разрывом и затем визуализируем их:
iex> doc = Inspect.Algebra.glue("a", " ", "b")
iex> Inspect.Algebra.format(doc, 80)
["a", " ", "b"] Обратите внимание, что разрыв был представлен как есть, потому что мы не достигли предела строки. Как только это произойдет, он заменится новой строкой:
iex> doc = Inspect.Algebra.glue(String.duplicate("a", 20), " ", "b")
iex> Inspect.Algebra.format(doc, 10)
["aaaaaaaaaaaaaaaaaaaa", "\n", "b"] concat(docs)
concat([t]) :: doc_cons
Конкатенирует список документов.
concat(x, y)
concat(t, t) :: doc_cons
Конкатенирует две сущности документа.
Примеры
iex> doc = Inspect.Algebra.concat "hello", "world" iex> Inspect.Algebra.format(doc, 80) ["hello", "world"]
empty()
empty() :: :doc_nil
Возвращает сущность документа, используемую для представления пустоты.
Примеры
iex> Inspect.Algebra.empty :doc_nil
fold_doc(list, fun)
fold_doc([t], (t, t -> t)) :: t
Складывает список сущностей документов в сущность документа с использованием функции, которая передается в качестве первого аргумента.
Примеры
iex> doc = ["A", "B"] iex> doc = Inspect.Algebra.fold_doc(doc, fn(x, y) -> ...> Inspect.Algebra.concat [x, "!", y] ...> end) iex> Inspect.Algebra.format(doc, 80) ["A", "!", "B"]
format(d, w)
format(t, non_neg_integer | :infinity) :: iodata
Функция форматирования.
Принимает максимальную ширину и документ для печати в качестве аргументов и возвращает представление данных ввода/вывода наилучшей компоновки документа для соответствия заданной ширине.
glue(x, y)
glue(t, t) :: doc_cons
Вставляет разрыв между двумя документами. См. break/1 для получения дополнительной информации.
glue(x, g, y)
glue(t, binary, t) :: doc_cons
Вставляет разрыв, переданный во втором аргументе, между двумя документами, первым и третьим аргументами.
group(d)
group(t) :: doc_group
Возвращает группу, содержащую указанный документ.
Примеры
iex> doc = Inspect.Algebra.group( ...> Inspect.Algebra.concat( ...> Inspect.Algebra.group( ...> Inspect.Algebra.concat( ...> "Hello,", ...> Inspect.Algebra.concat( ...> Inspect.Algebra.break, ...> "A" ...> ) ...> ) ...> ), ...> Inspect.Algebra.concat( ...> Inspect.Algebra.break, ...> "B" ...> ) ...> )) iex> Inspect.Algebra.format(doc, 80) ["Hello,", " ", "A", " ", "B"] iex> Inspect.Algebra.format(doc, 6) ["Hello,", "\n", "A", " ", "B"]
line(x, y)
line(t, t) :: doc_cons
Вставляет обязательный перевод строки между двумя сущностями документа.
Примеры
iex> doc = Inspect.Algebra.line "Hughes", "Wadler" iex> Inspect.Algebra.format(doc, 80) ["Hughes", "\n", "Wadler"]
nest(x, i)
nest(t, non_neg_integer) :: doc_nest
Вкладывает сущность документа x позиций глубоко.
Вкладывание будет добавлено к переводу строк.
Примеры
iex> doc = Inspect.Algebra.nest(Inspect.Algebra.glue("hello", "world"), 5)
iex> Inspect.Algebra.format(doc, 5)
["hello", "\n ", "world"] space(x, y)
space(t, t) :: doc_cons
Вставляет обязательный одиночный пробел между двумя сущностями документа.
Примеры
iex> doc = Inspect.Algebra.space "Hughes", "Wadler" iex> Inspect.Algebra.format(doc, 80) ["Hughes", " ", "Wadler"]
surround(left, doc, right)
surround(binary, t, binary) :: t
Оборачивает документ символами.
Размещает документ между левой и правой ограничивающими скобками, вкладывая его. Документ помечается как группа, чтобы показать максимально возможную краткость вместе.
Примеры
iex> doc = Inspect.Algebra.surround "[", Inspect.Algebra.glue("a", "b"), "]"
iex> Inspect.Algebra.format(doc, 3)
["[", "a", "\n ", "b", "]"] surround_many(left, docs, right, opts, fun, separator \\ ",")
surround_many(binary, [any], binary, Inspect.Opts.t, (term, Inspect.Opts.t -> t), binary) :: t
Картирует и склеивает коллекцию элементов.
Использует заданные левую и правую стороны в качестве ограничивающих и разделитель для каждого элемента. Может быть передан лимит, который, как только будет достигнут, прекращает склеивание и выводит «…» вместо этого.
Примеры
iex> doc = Inspect.Algebra.surround_many("[", Enum.to_list(1..5), "]",
...> %Inspect.Opts{limit: :infinity}, fn i, _opts -> to_string(i) end)
iex> Inspect.Algebra.format(doc, 5) |> IO.iodata_to_binary
"[1,\n 2,\n 3,\n 4,\n 5]"
iex> doc = Inspect.Algebra.surround_many("[", Enum.to_list(1..5), "]",
...> %Inspect.Opts{limit: 3}, fn i, _opts -> to_string(i) end)
iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary
"[1, 2, 3, ...]"
iex> doc = Inspect.Algebra.surround_many("[", Enum.to_list(1..5), "]",
...> %Inspect.Opts{limit: 3}, fn i, _opts -> to_string(i) end, "!")
iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary
"[1! 2! 3! ...]" to_doc(map, opts)
to_doc(any, Inspect.Opts.t) :: t
Преобразует структуру Elixir в документ алгебры в соответствии с протоколом inspect.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.3.4/Inspect.Algebra.html