#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