Как стать автором
Обновить

Комментарии 12

Классный разбор внутренностей Elixir'a, спасибо!
А вы не могли бы подробнее описать, почему решили остановиться на Erlang'е? Явно ведь не из-за протоколов — статья подводит к тому, что они удобны, а оверхед у них небольшой.

Тому есть несколько причин.

1. Erlang в нашей компании стал использоваться еще до появления Elixir. Соответственно у нас есть множество библиотек и устоявшихся практик как писать код на Erlang быстро и красиво. Взаимодействие Elixir -> Erlang писать достаточно легко, а вот Erlang -> Elixir значительно сложнее. К тому же сам по себе код на языке Erlang, хоть и выглядит поначалу непривычно, из-за своей простоты (малого количества синтаксических конструкций) довольно легко как читать, так и писать (особенно, после того как добавились мапы).
А конструкции как Protocols или pipe оператор вполне можно «повторить».

2. Erlang у нас используется не только для Web API но и для написания внутренних БД (например есть проект riak-core) и очень часто. Elixir же развивается в основном вокруг framework-a Phoenix и в таких проектах не дает ощутимых преимуществ.

3. Erlang стабильнее Elixir и «детские болезни» прошел уже давно. А для нас важна стабильность.
А можно подробнее про повторение пайп оператора? А то оно все или смотрится чужеродно, или превращается в лисп.

Как замена pipe чаще всего используется каррирование, замыкания и свертки.


... 
Output = pipe(Input, [
    fetch_users(),
    update_users(),
    store_users_in_database(DbConnection)
]),
...

где pipe/2 — простая свертка, например.


pipe(Data, Funs) ->
    lists:foldl(fun(F, D) -> F(D) end, Data, Funs).

плюс в том что на таких pipe-ах можно построить нечто похожее на монады.


pipe(_Bind, Data, []) -> 
    Data;
pipe(Bind, Data, [H|T]) -> 
    Bind(Data, fun(D) -> pipe(Bind, H(D), T) end).

maybe(F, {just, Data}) -> F(Data);
maybe(F, nothing) -> nothing.

Usage


1> m:pipe(fun m:maybe/2, {just, 11}, [
    fun(A) -> 
        case A > 10 of 
            true -> {just, A}; 
            false -> nothing 
        end 
    end, 
    fun(A) ->  {just, A*2} end
]).

{just, 22}.

или, если причесать через каррирование,


filter_gt(A) -> fun(B) ->
    case A > B of
        true -> {just, A}:
        false -> nothing
    end
end.

do_mult(A) -> fun(B) -> {just, A*B} end.

то будет просто


1> m:pipe(fun m:maybe/2, {just, 11}, [
    m:filter_gt(10),
    m:mult(2)
]).

{just, 22}

но чаще используется pipe не на столько абстрактный, а под конкретный случай, например ok/error.


pipe(D, []) -> D;
pipe({ok, D}, [H|T]) -> pipe(H(D), T);
pipe({error, _}=Err, _) -> Err.

Конечно не сравнится с do нотацией Haskell или for в Scala, но жить можно :)


Очень хорошо такой подход себя показал в нашей библиотеке для работы с Postgres


1> repo:all(m_weather, [
      q:where(fun([#{city := City}]) -> pg_sql:in(City, [<<"Kraków">>, <<"Moscow">>]) end),
      q:order_by(fun([#{temp_lo := T}]) -> [{T, asc}] end),
      q:limit(10)
   ]).

Но также у него есть один минус Dialyzer не сможет провести детальную проверку типов, если State, который передается сквозь функции, меняет тип.


К слову, я экспериментировал с добавлением pipe оператора в нативный синтаксис Erlang и это оказалось проще чем я думал :)

А как решение на foldl'е по производительности, не замеряли? Я имею в виду, если тоже самое переписать просто в последовательный вызов функций. Мы используем Erlando, но там парс-трансформы и проект, видимо, уже заброшен.

Если боитесь за производительность foldl можно использовать -compile(inline_list_funcs).


Erlando я тоже использую, но только в собственных pet project-ах.

Особенно Александр Дюма понравился на картинке.
НЛО прилетело и опубликовало эту надпись здесь
У Айнстайна же лицо овальное, а тут явно круглое.
НЛО прилетело и опубликовало эту надпись здесь

Действительно, "декомпилировать beam-файлы и посмотреть, что же в итоге получилось", зачастую является лучшим способом понять, что же делает компилятор Эликсира.

У такого подхода есть один несущественный минус – вы не можете определить несколько реализаций протокола для одного и того же типа

А вам нужна такая возможность?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий