html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Elixir из песочницы

Здравствуйте, сегодня я Вам расскажу о современном языке программирования под BeamVM (или ErlangVM).
Первая часть является неполным введением в основы, а вторая часть статьи показывает на простых примерах главные особенности языка, новые для erlang-разработчика.

Два года назад вышла 0.1 версия elixir, которая и была представлена хабрасообществу раньше.

Цитата:

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

На данный момент, elixir стал самым популярным языком программирования (естественно, помимо erlang-а), построенным поверх BeamVM. Вплоть до того, что автор erlang Joe Armstrong посвятил статью, а Dave Thomas написал книгу. За два года очень многое изменилось, язык сильно стабилизировался и обрёл более или менее конечный вариант для версии 1.0. За это время, из elixir исчезла объектная модель, остался Ruby-подобный синтаксис, но добавился метапрограмминг и полиморфизм, которые органично, в отличие от объектно-ориентированной парадигмы вписываются в Beam VM.

Новое в Elixir-е:

  • Ruby-подобный синтакс (семантика не как в Ruby)
  • Полиморфизм с помощью протоколов
  • Метапрограммирование
  • Стандартизированная библиотека
  • «First class shell»
  • И ещё много-много другого

При этом он компилируется в beam-код erlang-а; elixir также позволяет Вам вызывать модули erlang без необходимости преобразовывать типы данных, поэтому нет никакой потери в производительности при вызове кода erlang.

Чтобы опробовать у себя, можно скачать его с гитхаба:

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


Или установить прекомпилированную версию.

А так же для обладателей Fedora, Mac OS или Arch Linux можно установить elixir через пакет-менеджер:
  • Homebrew для Mac OS X:
    1. $ brew tap homebrew/versions
      $ brew install erlang-r16
      
    2. Если установлена предыдущая версия erlang-а, то нужно link-овать новую версию erlang-а:
      $ brew uninstall erlang
      $ brew link erlang-r16
      
    3. Установка elixir-а:
      $ brew update
      $ brew install elixir
      


  • Fedora 17+ и Fedora Rawhide: sudo yum -y install elixir
  • Arch Linux: Elixir доступен через AUR: yaourt -S elixir


В elixir-е имеется интерактивная консоль iex, в которой можно сразу же всё и попробовать. В отличие от erlang-а в консоли elixir-а можно создавать модули и рекорды, как будет показано ниже.

Комментарий:
# This is a commented line


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


Пример из консоли:

$ bin/iex

defmodule Hello do
 def world do
 IO.puts "Hello World"
 end
end
Hello.world

Типы данных в elixir-е такие же, как и в erlang-е:
1     # integer
0x1F  # integer
1.0   # float
:atom # atom / symbol
{1,2,3} # tuple
[1,2,3] # list
<<1,2,3>> # binary


Строки в elixir-е, как и в erlang-e могут быть представлены через списки или через binary:

'I am a list'
"I am a binary or a string"
name = "World"
"Hello, #{name}" # => string interpolation

В отличие от erlang, elixir использует везде binary, как стандартную имплементацию строк из-за скорости и компактности их перед списками букв.

A так же есть многострочные строки:
"""
This is a binary
spawning several
lines.
"""


Вызов функций, мы уже видели выше для модуля, но можно и так, опуская скобки:
div(10, 2)
div 10, 2

Хороший стиль программирования для elixir-а рекомендует, если и опускать скобки, то при использовании макро.
Coding Style в стандартной библиотеке говорит о том, что для вызова функций скобки должны быть.

Переменные в elixir являются mutable:
x = 1
x = 2


Изменять переменные можно только между выражениями, а внутри одного выражения это будет по-прежнему match. При этом сохранился весь pattern matching из erlang и при этом можно с помощью ^ делать их неизменяемыми как в erlang-е:
{x, x} = {1,2} # => ** (MatchError) no match of right hand side value: {1,2}
{a, b, [c | _]} = {1,2,["a", "b", "c"]} # => a = 1 b = 2 c = "a"

a = 1 # => 1
a = 2 # => 2
^a = 3 # => ** (MatchError) no match of right hand side value: 3


Подробнее ознакомиться с синтаксисом, возможностями и особенностями elixir-а можно здесь:
Официальный туториал
Crash Курс для erlang-разработчиков
Неделя с elixir-ом. Статья Joe Armstrong об elixir-е
Книга Programming Elixir от Dave Thomas, там же есть два видеотуториала и несколько фрагментов из книги
Официальная документация

После того, как я сам начал программировать на elixir-е, смотреть на код erlang, который создаётся часто через copy-paste с изменением одного значения(а такая необходимость есть почти в каждом проекте, который я встречал) или постоянные повторения определённого паттерна, которые увеличивают код, мне так и хочется переписать их грамотно на elixir-е.

А сейчас хотелось бы показать на простых примерах нововведения для erlang-разработчика, a именно метапрограммирование, полиморфизм, а также синтаксический сахар, которые сильно упрощают код.

Пример( «Everything is an expression» ):
defmodule Hello do
  def world do
    IO.puts "Hello World"
  end
end


Запищем его в фаил и скомпилируем его так:

$ elixirc hello.ex


Теперь давайте изменим его немного:
defmodule Hello do

  IO.puts "Hello Compiler"
  def world do
    IO.puts "Hello World"
  end
end

Теперь попробуем два
defmodule Hello do
  if System.get_env("MY_ENV") == "1" do
    def world do
      IO.puts "Hello World"
    end
  else
    def world do
      IO.puts "Hello World with my Variable = 1"
    end
  end
end

А теперь, попробуем сгенерировать код.
В erlang-коде часто можно встретить такой или подобный код:
my_function(bad_type) -> 1;
my_function(bad_stat) -> 2;

.......
my_function(1) -> bad_type;
my_function(2) -> bad_stat;
.....

В elixir-е, мы можем получить ту же скорость работы функции, не повторяясь, если будем генерировать те же самые функции во время компиляции:
list = [{:bad_type, 1}, {:bad_stat, 2}, ...]
Enum.map(list, fn({type, num}) ->
  def my_function(unquote(type)) do
    unquote(num)
  end
  def my_function(unquote(num)) do
    unquote(type)
  end
end)

Это взято из реального кода:
в одну сторону и в другую сторону
И в ту и в другую сторону, на elixir-е

Пример использования(с list compression, который в таких случаях используется намного чаще) в самом elixir-е можно увидеть, например здесь:
github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/string.ex#L478-L486

Макро в elixir-e действуют, как в clojure(программисты lisp-а будут чувствовать себя, как дома), у любого кода можно увидеть его AST:
quote do: 1+1 # => {:+,[context: Elixir, import: Kernel],[1,1]}
quote do: {1,2,3,4} # => {:"{}",[],[1,2,3,4]}
quote do: sum(1,2) # => {:sum,[],[1,2]}
quote do: sum(1, 2 + 3, 4) # => {:sum,[],[1,{:+,[context: Elixir, import: Kernel],[2,3]},4]}

Как видно из примеров, AST состоит из кортежей с тремя элементами: {name, meta, arguments}
Теперь, попробуем написать наше первое макро:
defmodule MyMacro do
  defmacro unless(clause, options) do
    quote do: if(!unquote(clause), unquote(options))
  end
end


Теперь используем наше макро:
require MyMacro
MyMacro.unless 2 < 1, do: 1 + 2


Полиморфизм:
list = [{:a, 1}, {:b, 2}, {:c, 3}, {:d, 4}, {:e, 5}, {:f, 6}, {:g, 7}, {:h, 8}, {:k, 9}]

Enum.map(list, fn({a, x}) -> {a, x * 2} end)

dict = HashDict.New(list)

Enum.map(dict, fn({a, x}) -> {a, x * 2} end)

file  = File.iterator!("README.md")
lines = Enum.map(file, fn(line) -> Regex.replace(%r/"/, line, "'") end)
File.write("README.md", lines)

Пример показывает, что мы можем использовать библиотеку Enum над любым типом данных, который имплементирует протокол Enumerable.

Имплементация для протоколоа может находиться где угодно, независимо от самого протокола: главное, чтобы скомпилированный код находился там, где BeamVM может его найти(т.е. в :source.get_path). Т.е. например, Вы можете расширять существующие библиотеки, не изменяя их код для своих типов данных.

Ещё один интересный встроенный протокол — это access protocol — возьмём на примере верхнего списка символ-значение:
list = [{:a, 1}, {:b, 2}, {:c, 3}, {:d, 4}, {:e, 5}, {:f, 6}, {:g, 7}, {:h, 8}, {:k, 9}]

list[:a] # => 1


Мы сделаем очень простой пример с бинарным деревом, который будет находиться в записи(record) Tree и для нашего дерева мы тоже имплементируем Access протокол.
defmodule TreeM do
  def has_value(nil, val), do: nil
  def has_value({{key, val}, _, _}, key), do: val
  def has_value({_, left, right}, key) do
    has_value(left, key) || has_value(right, key)
  end

end
defrecord Tree, first_node: nil

defimpl Access, for: Tree do
  def access(tree, key), do: TreeM.has_value(tree.first_node, key)
end


Теперь точно так же мы можем находить наши значения через Access Protocol
tree = Tree.new(first_node: {{:a, 1}, {{:b, 2}, nil, nil}, {{:c, 3}, nil,  nil}})
tree[:a] # => 1

Протоколы дают полиморфизм.

И теперь, немного синтаксического сахара, который упрощает написание и чтение кода в определённых ситуациях.
[{:a, 1}] можно писать так: [a: 1]

Точно так же, часто приходиться писать такие конструкции, как:
func3(func2(func1(list))), несмотря на то, что вызов функции func1 произойдёт первым, мы пишем вначале func3 или должны вводить переменные, как в этом случае:
file  = File.iterator!("README.md")
lines = Enum.map(file, fn(line) -> Regex.replace(%r/"/, line, "'") end)
File.write("README.md", lines)


C помощью оператора pipeline (|>) мы можем переписать наш пример так:
lines = File.iterator!("README.md") |> Enum.map(fn(line) -> Regex.replace(%r/"/, line, "'") end)
File.write("README.md", lines)

В библиотеке elixir-а стандартизировано субъект идёт первым аргументом. И это даёт возможность с помощью |> оператора, который подставляет результат предыдущего действия как первый аргумент функции в следующий вызов, писать более понятный, компактный и последовательный код.

Ещё, мы можем упростить этот пример, используя curry или partials в простых случаях:
lines = File.iterator!("README.md") |> Enum.map( Regex.replace(%r/"/, &1, "'") )
File.write("README.md", lines)


Я думаю, Elixir будет интересен erlang-разработчикам, которые хотят улучшить качество своего кода, продуктивность, и опробовать метапрограммирование в действии. Аналогично, разработчики с других языков и платформ также проявят к нему интерес. Например те, кто хотели бы опробовать BeamVM, но не решались из-за синтаксиса erlang-а или сумбура в его библиотеках. Здесь важным достоинством elixir-а является стандартизированная и компактная стандартная библиотека(Standard Library).
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

1

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • habrahabr.ru
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции