- PVSM.RU - https://www.pvsm.ru -
Это произошло внезапно, но принесло море радости. Наконец-то книжное издательство обратило внимание на заинтересованность разработчиков Эликсиром и выпустило первую книгу по этому языку на русском [1]. Выбор издания для перевода ожидаем — это материал для людей, которые хотят познакомиться с языком либо уже начали знакомство и готовы узнать о возможностях больше.
Эликсир [2] — динамический, функциональный язык программирования, спроектированный для создания масштабируемых и легко поддерживаемых приложений. Основан на Erlang VM, эффективной для распределённых, отказоустойчивых систем с низкой задержкой, в то же время с успехом применяемой в веб-разработке и сфере встроенного ПО.
«Введение в Elixir» [1] — стандартный представитель литературы по языкам программирования. Рассказ ведётся последовательно, от основ синтаксиса к продвинутым модулям и техникам. Примеры синтетические, но при этом иллюстрируют текст так, что сразу становится понятно о чём идёт речь. Учитывая, что язык — выразительный, а набор инструментов, доставшийся в наследство от Эрланга впечатляет, скучать не приходится.
Далее рассмотрю каждую из глав подробнее.
Здесь всё стандартно. Подготовка к работе с языком, объяснение основы основ и коротенький мастер-класс по работе с интерактивной оболочкой [3].
Спустя 20 минут работы с книгой, нас уже знакомят с основной прелестью и красотой языка — функцией. Казалось бы, ничего необычного — просто один из элементов языка. Но на деле, функции в Эликсире — его фундамент.
И уже здесь раскрываются первые необычные возможности языка. Например, объединение функций через пайпы, когда подобная конструкция
Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end)
превращается в элегантного вида
[1, [2], 3]
|> List.flatten
|> Enum.map(fn x -> x * 2 end)
Или как вам такая особенность? Добавляя комментарии к функциям можно тут же получать полноценную документацию, встроенными в язык средствами.
Опыт работы с книгой зависит от того, с какими языками вы уже знакомы. Если ранее вы не сталкивались с функциональными языками или не знакомы с синтаксисом Руби, то уже здесь начнутся откровения.
Во-первых, в Эликсире используется тип данных атом. Вроде бы ничего особенного, элементы этого типа имеют значение, совпадающее с именем.
iex(1)> :test
:test
Но такая простая идея существенным образом (при использовании других механизмов языка) оказывают влияние на стиль программирования на Эликсире.
defmodule Drop do
def fall_velocity(:earth, distance) do
:math.sqrt(2 * 9.8 * distance)
end
def fall_velocity(:moon, distance) do
:math.sqrt(2 * 1.6 * distance)
end
def fall_velocity(:mars, distance) do
:math.sqrt(2 * 3.71 * distance)
end
end
Например, здесь не переопределяется одна и та же функция трижды. На самом деле это 3 разные функции, каждая из которых может быть выбрана через сопоставлении с образцом первого аргумента-атома.
Это основная техника языка, с помощью которой можно творить чудеса. И в книге рассказывается как это делать. Будь то с использованием охранных условий либо более сложных, чем обычные атомы, сопоставлений с образцом.
Программы на функциональных языках принято писать больше с использованием рекурсии, чем через стандартные циклы. О том, как правильно написать рекурсию, которую сможет оптимизировать компилятор, читайте в этой главе. Благодаря сопоставлению с образцом, которое используется и в охранных условиях, и в логических выражениях, рекурсия получается очень элегантной и необычной.
defmodule Fact do
def factorial(n) do
factorial(1, n, 1)
end
defp factorial(current, n, result) when current <= n do
new_result = result * current
IO.puts("#{current} yields #{new_result}.") factorial(current + 1, n, new_result)
end
defp factorial(_current, _n, result) do
IO.puts("Finished!")
result
end
end
Одним из основных технических отличий Эликсира от Эрланга является полная переработка механизма работы строк. Теперь это не просто списки символов, а полноценный бинарный тип данных, который может поддерживать Юникод. И именно благодаря строкам мы можем вступать во взаимодействие с пользователем.
Эликсир имеет превосходную поддержку списков, длинных последовательностей значений. Они помогают оценить достоинства рекурсии и позволяют выполнить большой объем работы с минимальными усилиями. Хоть это и стандартный тип данных для функциональных языков, здесь есть о чём поговорить.
defmodule Pascal do
def add_row(initial) do
add_row(initial, 0, [])
end
def add_row([], 0, nal) do
[0 | nal]
end
def add_row([h | t], last, new) do
add_row(t, h, [last + h | new])
end
end
Вот такое вот функциональное программирование с человеческим лицом.
Меня порой спрашивают. Раз в Эликсире нет объектов, то как же нам работать со структурированными данными? Кортежи и списки — это хорошо, но они не позволяют достать значение по имени. Эликсир, хоть и молодой, но уже зрелый (даже продакшн реди) язык. Поэтому разработчики предусмотрели механизмы для решения этой задачи. В Эликсире есть типы данных, в которых можно получать значение по ключу. И в этой главе рассматривается именно они — от словаря до структуры.
Функции высшего порядка, или функции, принимающие в аргументах другие функции, помогают Эликсиру проявиться во всем его блеске. Нельзя сказать, что в других языках невозможно реализовать подобные функции, — это возможно почти в любых языках, но в Эликсире функции высшего порядка интерпретируются как естественная часть языка, а не как искусственное и чужеродное образование.
Не самая интересная глава, но узнать об этих возможностях будет не лишним.
При описании Эликсира в качестве преимущества обычно упоминают некие процессы. Говорят, что они позволяют добиться распределённости, повышают скорость работы программы, используются при масштабировании и горячей замене кода, но совершенно не ясно что они собой представляют и как выглядят в рамках самого языка.
На самом деле, процессы — это ещё одна организационная единица программы, наравне с функциями и модулями, которая является независимым компонентом, способным принимать и отправлять сообщения. Работающая программа — это набор процессов.
Начинается разговор в этой главе с интерактивной оболочки, которая также является процессом. О процессах говорится много и подробно, также рассматриваются и дополнительные инструменты для работы с ними.
С отладкой в Эликсире [4] пока не всё гладко, так как не существует полноценных нативных инструментов. Самое популярное — Pry
(который пришёл из Руби) и :dbg
(из Эрланга). На самом деле, ими вполне комфортно пользоваться, и в книге даётся неплохой разбор второго из них.
В программировании известны три основных класса ошибок: синтаксические ошибки, ошибки времени выполнения и семантические ошибки. Компилятор Эликсира обнаруживает и сообщает о синтаксических ошибках. Остаются логические ошибки, когда вы требуете от Эликсира одно, имея в виду другое. Журналирование и трассировка могут помочь в поиске подобных ошибок, но всё же лучше постараться предотвратить их появление с самого начала. И в этом вам помогут статический анализ, спецификации типов и модульное тестирование. Обо всём этом рассказывается в этой главе.
Эликсир имеет очень нетривиальные возможности в этих областях. Например, встроенные в документацию тесты:
defmodule Drop do
@doc """
Вычисляет скорость падающего объекта на указанном объекте
планемо (объекте с планетарной массой)
iex(1)> Drop.fall_velocity(:earth, 10)
14.0
iex(2)> Drop.fall_velocity(:mars, 20)
12.181953866272849
iex> Drop.fall_velocity(:jupiter, 10)
** (CaseClauseError) no case clause matching: :jupiter
"""
def fall_velocity(planemo, distance) do
gravity = case planemo do
:earth -> 9.8
:moon -> 1.6
:mars -> 3.71
end
:math.sqrt(2 * gravity * distance)
end
end
Теперь, можно быть уверенными, что документация всегда будет актуальной!
Как бы нам ни хотелось иметь чистые функции, на практике это невозможно, ведь данные нужно где-то хранить. Для этого у Эрланга есть куча встроенных инструментов, которыми к счастью можно пользоваться и из Эликсира. В этой главе рассматриваются ETS и Mnesia.
Просто представьте, что вам больше не понадобится Редис, в качестве внешней зависимости. Ведь его «заменитель» встроен прямо в язык и поддерживается из коробки.
Все, приходящие в мир Эрланга и Эликсира, слышат о неком OTP, который обсуждают более опытные коллеги. На подкорке откладывается, что это какая-то очень крутая штука, невероятно полезная и просто мастхев в повседневной разработке. Но что же это такое, абсолютно не ясно.
Оказывается, OTP — это фреймворк для написания распаралелленных и высоконадёжных приложений. Он использует все фишки виртуальной машины Эрланга и позволяет программистам задумываться только о бизнес-логике, а не о деталях реализации.
Самыми популярными модулями являются Supervisor и GenServer. Выглядят они так:
defmodule DropServer do
use GenServer
defmodule State do
defstruct count: 0
end
def start_link do
GenServer.start_link(__MODULE__, [], [{:name, __MODULE__}])
end
def init([]) do
{:ok, %State{}}
end
def handle_call(request, _from, state) do
distance = request
reply = {:ok, fall_velocity(distance)}
new_state = %State{count: state.count + 1}
{:reply, reply, new_state}
end
def handle_cast(_msg, state) do
IO.puts("So far, calculated #{state.count} velocities.")
{:noreply, state}
end
def handle_info(_info, state) do
{:noreply, state}
end
def terminate(_reason, _state) do
{:ok}
end
def code_change(_old_version, state, _extra) do
{:ok, state}
end
def fall_velocity(distance) do
:math.sqrt(2 * 9.8 * distance)
end
end
Узнать о них подробнее можно тут [5] и тут [6]. Либо в текущей главе книги.
А ещё Эликсир предлагает штуку, о которой мечтают все эрлангисты — утилиту Mix.
Её обзор тоже есть в книге.
Следующая возможность, которая выгодно отличает Эликсир от Эрланга — продвинутое метапрограммирование. Оно реализовано через создание макросов. Внешне макросы очень похожи на функции, отличаясь только тем, что начинаются с инструкции defmacro
вместо def
. Однако макросы действуют совершенно иначе, чем функции. Благодаря этому можно создавать крутой DSL, не усупающий рубишному.
Ну и завершается книга такой важной темой как Феникс. Это веб-фреймворк, который так и хочется сравнить с Рельсами. Феникс унаследовал рельсовую философию и некоторые подходы, хотя сейчас постепенно отодвигается в свою сторону. Но нельзя не отметить, что Феникс является таким же двигателем для Эликсира, как и в своё время Рельсы для Руби.
Вводный курс по Фениксу можно прочитать в книге либо в этой серии статей [7], которую я перевожу для Хабра.
Книга исключительно годная. Я уже несколько месяцев занимаюсь проектом Вунш, где мы знакомим русскоязычных читателей с прекрасным Эликсиром. И мне всё равно было интересно читать книгу, удалось почерпнуть нюансы при работе со знакомыми частями языка и узнать о других возможностях, с которыми не приходилось раньше сталкиваться.
Что важно отметить, и за что я переживал больше всего — это перевод. И к счастью, он получился довольно удачным. Надмозг практически отсутствует, а переводы терминов, хоть и хотелось бы оставить чуть более англифицированными, слух не режут. Такая дань академичности вполне уместна.
Надеюсь, мой обзор вам пригодится. Всем хорошего дня и побольше полезных книг!
Автор: Ярослав
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ruby/251804
Ссылки в тексте:
[1] первую книгу по этому языку на русском: http://bit.ly/2ozje4k
[2] Эликсир: http://elixir-lang.org/
[3] мастер-класс по работе с интерактивной оболочкой: https://wunsh.ru/articles/getting-started-with-iex-in-elixir.html
[4] отладкой в Эликсире: https://wunsh.ru/articles/elixir-debugging.html
[5] тут: https://wunsh.ru/articles/how-supervisors-work-in-elixir.html
[6] тут: https://wunsh.ru/articles/genstage-optimization.html
[7] в этой серии статей: https://habrahabr.ru/post/311088/
[8] подписывайтесь на нашу рассылку: https://wunsh.ru
[9] Источник: https://habrahabr.ru/post/325218/
Нажмите здесь для печати.