Может ли исходный код Erlang быть встроен в код Эликсира? Если да, то как?

#erlang #elixir

Вопрос:

Источник эликсира может быть введен с помощью кода.eval_string/3. Я не вижу упоминания о запуске необработанного кода Erlang в документах:

https://hexdocs.pm/elixir/Code.html#eval_string/3

Я пришел из мира Scala, в котором объекты Java могут вызываться с использованием синтаксиса Scala, а Scala компилируется в Java и отображается путем перехвата выходных данных компилятора (непосредственно генерируемых с помощью scalac).

У меня такое ощущение, что Elixir не предоставляет таких взаимодействующих функций и не позволяет вводить пользовательский Erlang во время выполнения. Так ли это на самом деле?

Ответ №1:

Вы можете использовать стандартные библиотечные модули erlang от Elixir, как описано здесь или здесь.

Например:

 def random_integer(upper) do
  :rand.uniform(upper) # rand is an erlang library
end
 

Вы также можете добавлять пакеты erlang в свои mix.exs зависимости и использовать их в своем проекте, если эти пакеты опубликованы на hex github или на нем.

Вы также можете использовать код erlang и elixir вместе в проекте, как описано здесь.

Так что да, вполне возможно вызвать код эрланга из эликсира.

Также возможно обратное, смотрите здесь для получения дополнительной информации:

Эликсир компилируется в байтовый код ЛУЧА (через абстрактный формат Erlang). Это означает, что код Elixir может быть вызван из Erlang и наоборот, без необходимости писать какие-либо привязки.

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

1. Также, как было задано в первоначальном вопросе, с Code.eval_string/3 : Code.eval_string(":rand.uniform(100)") #⇒ {38, []} .

2. Отлично. Спасибо, что указали мне на документацию для этого.

3. Принимаю, потому что на документацию есть ссылки, но также смотрите ответ @Hauleth, в котором есть очень хорошие примеры.

Ответ №2:

Расширяя то, что написал @zwippie:

Все удаленные вызовы функций (под этим я подразумеваю вызов функции с явно заданным модулем/псевдонимом) имеют форму:

 <atom with module name>.<function name>(<arguments>)

# Technically it is the same as:
# apply(module, function_name_as_atom, [arguments])
 

И все «имена модулей в верхнем регистре» в Elixir-это просто атомы:

 is_atom(Foo) == true
Foo == :"Elixir.Foo" # => true
 

Таким образом, с точки зрения Эликсира, нет никакой разницы между вызовом функций Erlang и функциями Эликсира. Это просто другой атом, переданный в качестве принимающего модуля.

Таким образом, вы можете легко вызывать модули Erlang из Elixir. Это означает, что без особых хлопот вы также сможете скомпилировать Erlang AST из Эликсира:

 "rand:uniform(100)"
|> :merl.quote()
|> :erl_eval.expr(#{})
 

Нет необходимости в каком-либо мысленном переводе.


Кроме того, вы можете без каких-либо проблем смешивать код Erlang и Elixir в одном проекте Mix. С древовидной структурой, такой как:

 .
|`- mix.exs
|`- src
|  `- example.erl
 `- lib
   `- example.ex
 

Где example.erl :

 -module(example).

-export([hello/0]).

hello() -> <<"World">>.
 

И example.ex :

 defmodule Example do
  def print_hello, do: IO.puts(:example.hello())
end
 

Вы можете скомпилировать проект и запустить его с помощью

 mix run -e "Example.print_hello()"
 

И убедитесь, что модуль Erlang был успешно скомпилирован и выполнен из кода Elixir в том же проекте без проблем.

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

1. Отлично, очень приятно, спасибо за примеры.

Ответ №3:

Еще одна вещь, на которую следует обратить внимание при вызове кода erlang из elixir. эрланг использует чарлисты для строк. При вызове функции erlang, которая принимает строку, преобразуйте строку в список символов и преобразуйте возвращенную строку в строку.

Примеры:

 iex(17)> :string.to_upper "test"
** (FunctionClauseError) no function clause matching in :string.to_upper/1

    The following arguments were given to :string.to_upper/1:

        # 1
        "test"

    (stdlib 3.15.1) string.erl:2231: :string.to_upper/1
iex(17)> "test" |> String.to_charlist() |> :string.to_upper
'TEST'
iex(18)> "test" |> String.to_charlist() |> :string.to_upper |> to_string
"TEST"
iex(19)>
 

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

1. Спасибо за совет. Для справки в этой документации описывается разница между строкой и чарлистом: elixirschool.com/en/lessons/basics/strings