Elixir (язык программирования)

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Elixir
Official Elixir logo.png
Класс языка мультипарадигмальный: функциональный, параллельный, распределённый, процессо-ориентированный
Появился в 2012
Разработчик Хосе Валим[d]
Расширение файлов .ex или .exs
Выпуск 1.9.0 / 24 июня 2019 (2019-06-24)[1]
Система типов динамическая, строгая
Испытал влияние Erlang, Ruby, Clojure
Лицензия Apache License 2.0[2]
Сайт elixir-lang.org
Платформа Erlang

Elixir — функциональный, распределённый язык программирования общего назначения, который работает на виртуальной машине Erlang (BEAM). Построен поверх Erlang, что обеспечивает распределённость, отказоустойчивость, исполнение в режиме мягкого реального времени, метапрограммирование с макросами и полиморфизмом, реализованным через протоколы[3]. Использует Erlang/OTP для работы с деревьями процессов[4].

Создан Жозе Валимом (José Valim), ранее являвшимся одним из основных разработчиков фреймворка Ruby on Rails и сооснователем компании Plataformatec[5][6]. Его целью было включить более высокую расширяемость и производительность в Erlang VM, сохраняя совместимость с инструментами и экосистемой Erlang[7].

Возможности[править | править код]

Программы компилируются в байт-код для виртуальной машины Erlang (BEAM)[8]. Каждый элемент программы является выражением[8], функции языка Erlang могут быть вызваны без влияния на время исполнения из-за компиляции байт-кода в Erlang и наоборот.

Метапрограммирование дает возможность прямого манипулирования абстрактным синтаксическим деревом (АСД)[8]. Полиморфизм, реализованный через механизм протоколов, которые, как и в Clojure, обеспечивают механизм диспетчеризации (не стоит путать с множественной диспетчеризацией). Параллельное программирование — без разделения ресурсов, через передачу сообщений (модель акторов)[9]. На практике упор делается на рекурсии и функциях высшего порядка вместо применения циклов, основанных на побочных эффектах. Для реализации простого параллелизма использованы механизмы Erlang с упрощённым синтаксисом (например, Task)[8].

Реализованы ленивые вычисления и асинхронные коллекции с потоками, сопоставление с образцом[8].

Язык поддерживает Unicode и UTF-8-строки. Реализована поддержка документирования кода по синтаксису напоминающая строки документации языка Python, но в формате Markdown[8].

Описание языка[править | править код]

Типы данных[править | править код]

На низком уровне Elixir использует примитивные типы, доступные в виртуальной машине Erlang. Так, список — всего лишь упорядоченный набор значений.

Elixir имеет следующие встроенные типы данных (см. также типы данных Erlang)[10]:

На основе этих примитивных типов в Elixir в частности построены строки и структуры[10].

Модули[править | править код]

На основе встроенных типов данных можно строить более высокоуровневые абстракции. Для построения абстракций данных в языке функционального программирования Elixir используются модули. Например, Keyword является модулем Elixir, а его реализация основана на списке кортежей, и, естественно, с Keyword можно работать и как со списком[11]. Модули являются «чистыми» и не содержат собственного состояния как, например, объекты в языках, использующих ООП[12].

Например, аналогом "строка".downcase из Ruby в Elixir будет: String.downcase("строка"). Обычно экземпляр абстракции передаётся в функции модуля как первый аргумент.

Модули содержат функции, позволяющие создать абстракцию, делать запросы, а также модифицировать её (путём создания нового экземпляра). Следует заметить, что абстракции не могут содержать скрытых данных — они прозрачны для пользователей модуля. В то же время, модули могут содержать внутренние функции (определяемые с помощью defp), которые недоступны из других модулей[12].

Сравнение с Erlang[править | править код]

Elixir был задуман как улучшение Erlang, в частности, значительного упрощения синтаксиса. Одним из основных отличий является возможность повторного присваивания значений переменных. В Elixir не требуется завершать каждую команду точкой (по примеру Пролога), так как выражения разделяются переводом строки и точкой с запятой (;). В Elixir не требуется экспортировать функции модуля, тогда как в Erlang по умолчанию все функции недоступны из других модулей, если не упомянуты в директиве -export. Тем самым, синтаксис Elixir больше похож на синтаксис Ruby[6].

Примеры[править | править код]

Следующие примеры могут быть запущены в оболочке iex или могут быть сохранены в файле и запущены с помощью команды elixir <имя файла>.

Пример классической программы Hello world:

IO.puts "Hello World!"

Создание нового списка (List) на основе существующего с помощью спискового включения:

for n <- [1,2,3,4,5], rem(n,2) == 1, do: n*n
#=> [1, 9, 25]

Сопоставление с образцом:

[1, a] = [1, 2]
# a = 2

{:ok, [hello: a]} = {:ok, [hello: "world"]}
# a = "world"

Оператор конвейера (англ. pipe):

"3" |> String.to_integer() |> Kernel.*(2)
# 6

Бинарные данные и битовые строки[13]:

bb = <<20, 19, 3>>
# <<20, 19, 3>>
<<b1, b2, b3>> = bb
# <<20, 19, 3>>
b1
# 20
<<a :: 4, b :: 4>> = << 254 >>
# <<254>>
a
# 15
b
# 14

где bb — переменная с двоичными данными из трёх байт b1, b2, b3 (показан синтаксис сопоставления с образцом), а из числа 254 с помощью сопоставления с образцом выделяются в отдельные переменные a и b биты с первого по четвёртый и с пятого по восьмой.

Модули:

defmodule Fun do
  def fib(0), do: 0
  def fib(1), do: 1
  def fib(n) do 
    fib(n-2) + fib(n-1)  
  end
end

Порождение большого числа процессов в цикле:

for num <- 1..1000, do: spawn fn -> IO.puts("#{num * 2}") end

Асинхронное выполнение:

task = Task.async fn -> perform_complex_action() end
other_action()
Task.await task

Внутреннее представление кода:

quote do: (k = 1; k + 2)    # в результате даёт
{:__block__, [],
 [{:=, [], [{:k, [], Elixir}, 1]},
  {:+, [context: Elixir, import: Kernel], [{:k, [], Elixir}, 2]}]}

Инструментарий[править | править код]

Для работы с проектами на Elixir: создания новых, управления зависимостями, компиляции, тестирования, запуска на выполнение — имеется утилита автоматизации (англ. build tool) под названием Mix. Например, команда mix new myproject создаёт новый проект по шаблону, в результате чего появляется каталог проекта (версия Mix 1.1.1)[14]:

myproject/
├── config
│   └── config.exs
├── .gitignore
├── lib
│   └── myproject.ex
├── mix.exs
├── README.md
└── test
    ├── myproject_test.exs
    └── test_helper.exs

Где config содержит конфигурацию приложения, lib — исходный код, tests — тесты, mix.exs — конфигурацию проекта.

Примечания[править | править код]

  1. [1]
  2. elixir/LICENSE at master · elixir-lang/elixir · GitHub
  3. Elixir. José Valim. Дата обращения 17 февраля 2013.
  4. Thomas, 2014, When Processes Die.
  5. The core team
  6. 1 2 Mihalis Tsoukalos, «Elxir: Take a functional swig», Linux Format, issue 203, 2015
  7. Elixir - A modern approach to programming for the Erlang VM. Дата обращения 17 февраля 2013.
  8. 1 2 3 4 5 6 Elixir. Дата обращения 7 сентября 2014.
  9. Loder, Wolfgang. Erlang and Elixir for Imperative Programmers (неопр.). — "Chapter 16: Code Structuring Concepts", section title "Actor Model": Leanpub, 2015.
  10. 1 2 Thomas, 2014, Built-in Types.
  11. Thomas, 2014, An Aside—What Are Types?.
  12. 1 2 Jurić, 2019, Data abstractions.
  13. Jurić, 2019, 3. Control flow.
  14. Thomas, 2014.

Литература[править | править код]

  • Сенлорен С., Эйзенберг Д. Введение в Elixir = Introducing Elixir. — ДМК-Пресс, 2017. — 262 с. — ISBN 978-5-97060-518-9.
  • Dave Thomas. Programming Elixir. — Pragmatic Bookshelf, 2014. — 280 p. — ISBN 978-1-937785-58-1.
  • Simon St. Laurent, J. David Eisenberg. Introducing Elixir. — O’Reilly Media, 2014. — 210 p. — ISBN 978-1-4493-6999-6.
  • Chris McCord. Metaprogramming Elixir. — Pragmatic Bookshelf, 2015. — 120 p. — ISBN 978-1-68050-041-7.
  • Saša Jurić. Elixir in Action. — 2nd ed. — Manning Publications, 2019. — ISBN 9781617295027.
  • Bruce A. Tate, Ian Dees, Frederic Daoud, Jack Moffitt. Elixir // Seven More Languages in Seven Weeks. — Pragmatic Bookshelf, 2014. — 350 p. — ISBN 978-1-941222-15-7.

Ссылки[править | править код]