Erlang/OTP
March 2011 13

Elixir

Erlang является уникальной по своим возможностям платформой, и не смотря на это, язык до сих пор является экзотикой. Причин существует несколько. Например, тугая арифметика, непривычность синтаксиса, функциональность. Это не недостатки. Это просто вещи, с которыми большинство программистов не могут или не хотят работать.

Несколько дней назад Jose Valim опубликовал в своем репозитории проект языка, построенного поверх Erlang. Этот язык обладает простой объектной моделью и Ruby-подобным синтаксисом. Под катом выжимки из документации и видео, демонстрирующее простой пример.

disclaimer: %username%, прежде чем делать выводы насчет того, что умеет, а что не умеет elixir, просьба глазами пройтись хотя бы по readme.


Elixir — язык программирования, работающий поверх Erlang. Как Erlang, это — функциональный язык со строгими вычислениями, однократным присвоением и динамической типизацией, созданный, чтобы поддерживать распределенные, отказоустойчивые, безостановочные приложения с горячей заменой кода. Elixir позволяет Вам вызывать модули Erlang без необходимости преобразовать типы данных, поэтому нет никакой потери в производительности при вызове кода Erlang.

Основное различие между Elixir и Erlang — синтаксис и объектная ориентированность. Elixir обеспечивает очень простую объектную модель и синтаксис, большей частью основанный на Ruby.

В настоящее время главной задачей является разработка стандартной библиотеки. Большая часть существующей стандартной библиотеки написана на самом Elixir, и Вам не нужно знать Erlang, чтобы внести свой вклад в ее развитие. Достаточно будет знакомства с принципами OTP.

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


$ git clone https://github.com/josevalim/elixir.git
$ cd elixir
$ make test

$ bin/elixir -v
Elixir 0.1.0

Комментарии в Elixir, как и в Erlang, обозначаются через “%”:

% This is a commented line

Далее, “% =>” показывают значение выражения:

1 + 1 % => 2


Elixir поддерживает целые и дробные числа:

2 + 15       % => 17
- 13 * 10    % => -130
1986 - 1985  % => 1
5 / 2        % => 2.5
4 / 2        % => 2.0

Как в Ruby, любая конструкция является объектом. Мы можем вызывать методы у чисел:

-1.abs    % => 1
5.div(2)  % => 2

%surprise !
1.+(2)  % => 3


Атомы в Elixir называются Symbols (как в Ruby). Но синтиксис позаимствован у Lisp (Jose объяснил это в твиттере тем, что хочет ":" использовать в словарях):

'atom
'Atom
'atom_without_spaces
'"Atom with Spaces"


Списки являются наиболее полезной структурой в Elixir (как и в любом другом функциональном языке), могу содержать все, что угодно и имеют набор методов:

% Some list with elements
['atom, 1, 2, 3, { 'some, 'tuple }]

% An empty list
[]

[1, 2, 3].length       % => 3
['a, 'b, 'c][1]        % => 'b

[1, 2, 3] + [4, 5, 6]  % => [1,2,3,4,5,6]

Списки в Erlang и Elixir реализованы как связные списки, поэтому предварительное добавление элементов происходит намного быстрее, чем последующее:

list = [2,3,4]

% Don't do this:
[1]   + [2,3,4]  % => [1,2,3,4]
[0,1] + [2,3,4]  % => [0,1,2,3,4]

% Do this instead:
[1|list]    % => [1,2,3,4]
[0,1|list]  % => [0,1,2,3,4]

Настоящую силу списков получаешь, когда используешь их вместе с функциями

[1, 2, 3].map do (x)
  x * 2
end  % => [2, 4, 6]

[1, 2, 3].foldl 0, do (x, acc)
  acc + x
end  % => 6


Строки в Erlang представлены списком символов:

"hello" == [104, 101, 108, 108, 111]

Это накладно, поскольку каждый символ занимает 8 байт памяти (не бит!). Elixir реализует строки, в виде utf8 бинарных строк:

% The famous "hello world" string
"hello world"

% A string converted to its underlying binary:
"hello".to_bin  % => <<[104, 101, 108, 108, 111]>>

% A string converted to a char list:
"hello".to_char_list  % => [104, 101, 108, 108, 111]

% Strings are UTF-8
"Arrow ⇧ up".length  % => 10

Это существенное изменение. Строки являются единственными объектами, требующими преобразования:

% Converting a string_from_erlang to Elixir's String
String.new string_from_erlang

% Where string_from_erlang is either a binary:
<<[104, 101, 108, 108, 111]>>

% Or a char_list:
[104, 101, 108, 108, 111]

% Converting a string_from_elixir to Erlang
"string_from_elixir".to_bin
"string_from_elixir".to_char_list

Наконец, строки поддерживают интерполяцию:

"string #{'with} interpolation"  % => "string with interpolation"
"1 + 1 = #{1 + 1}"               % => "1 + 1 = 2"


Функции являются важной частью Elixir, как и любого другого функционального языка. Функции можно создавать с помощью «do» или "->":

my_function = do
  1 + 2
end

my_function() % => 3

another_function = ->
  1 * 2
end

another_function() % => 2


Как и Erlang, Elixir поддерживает Pattern matching и единичное присваивание.

% Let's bound the variable x to 'foo
x = 'foo

% Now let's match a tuple with other tuple.
% Since x is already bound, we are comparing x with 'baz and it will fail:
{ x, y } = { 'baz, 'bar }

% In this case, we compare 'x with 'foo and it matches.
% Since y is unbound, we assign 'bar to it:
{ x, y } = { 'foo, 'bar }

x  % => 'foo
y  % => 'bar

[h|t] = [1,2,3]
h  % => 1
t  % => [2,3]

% Raises an error because h was already assigned to 1 and 1 does not match 2
[h|t1] = [2,3,4]

Как и в Eralng, pattern matching используется в сигнатурах функций:

module Math
  def fibonacci(0)
    0
  end

  def fibonacci(1)
    1
  end

  def fibonacci(n)
    fibonacci(n - 1) + fibonacci(n - 2)
  end
end

Math.fibonacci(0)   % => 0
Math.fibonacci(1)   % => 1
Math.fibonacci(3)   % => 2
Math.fibonacci(10)  % => 55


Вызов методов Erlang весьма тривиален:

% Accessing the is_atom BIF from Erlang.
% This is the same as `is_atom(foo)` in Erlang.
Erlang.is_atom('foo)  % => true

% Accessing the function delete from module lists.
% This is the same as `lists:member(1, [1,2,3])` in Erlang.
Erlang.lists.member(1, [1,2,3]) % => true


Объектная модель Elixir имеет некоторые аспекты:
  • Динамический выбор реализации — когда вызывается метод, объект сам выбирает, какой код выполнить
  • Mixin'ы — объекты не содержат методов. Все методы запакованы в модули, которые подмешиваются в объекты.
  • Инкапсуляция — методы могут быть public, protected или private.
  • Открытая рекурсия — объекты имеют специальную переменную self, которая позволяет вызвать другие методы объекта не затрагивая цепочку вызовов.
  • Рефлексия — Elixir способен просматривать и модифицировать структуру объекта во времени исполнения.


object Person
  def constructor(name, age)
    { 'name: name, 'age: age }
  end

  def name
    @name
  end

  def age
    @age
  end

  def name(value)
    self.set_ivar('name, value)
  end
end

person = Person.name('john, 24)
another_person = person.name('john_doe)

person.name % => 'john
person.age  % => 24

another_person.name % => 'johh_doe
another_person.age  % => 24


Это описание малой части возможностей Elixir. В репозитории опубликована отличная обзорная документация. Ролик ниже иллюстрирует небольшой пример работы языка:

+31
21.1k 45
Comments 80
Top of the day