Erlang 源代码可以嵌入到 Elixir 代码中吗?如果是这样,怎么做?

Posted

技术标签:

【中文标题】Erlang 源代码可以嵌入到 Elixir 代码中吗?如果是这样,怎么做?【英文标题】:Can Erlang source code be embedded in Elixir code? If so, how? 【发布时间】:2021-11-08 22:32:18 【问题描述】:

Elixir 源可以使用 Code.eval_string/3 注入。我没有看到文档中提到运行原始 Erlang 代码:

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

我来自 Scala 世界,其中 Java 对象可以使用 Scala 语法调用,Scala 被编译成 Java 并通过拦截编译器输出(直接使用 scalac 生成)可见。

我感觉 Elixir 不提供这样的互操作功能,也不允许将自定义 Erlang 注入运行时。是这样吗?

【问题讨论】:

【参考方案1】:

从 elixir 调用 erlang 代码时需要注意的另一件事。 erlang 使用字符列表作为字符串。当你调用一个接受字符串的 erlang 函数时,将字符串转换为 charlist 并将返回的字符串转换为字符串。

例子:

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)>

【讨论】:

感谢您的提示。作为参考,本文档描述了字符串和字符列表之间的区别:elixirschool.com/en/lessons/basics/strings【参考方案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

所以从 Elixir 的角度来看,调用 Erlang 函数和 Elixir 函数没有区别。它只是作为接收模块传递的不同原子。

因此您可以轻松地从 Elixir 调用 Erlang 模块。这意味着您应该也可以在 Elixir 中轻松编译 Erlang AST:

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

不需要任何心理翻译。


此外,您可以毫无问题地在单个 Mix 项目中混合 Erlang 和 Elixir 代码。树形结构如下:

.
|`- 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 代码中成功编译和执行,没有问题。

【讨论】:

非常好,非常感谢您提供的示例。【参考方案3】:

您可以使用 Elixir 的 erlang 标准库模块,如 here 或 here 所述。

例如:

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

您也可以将 erlang 包添加到您的 mix.exs 依赖项中并在您的项目中使用它们,只要这些包发布在 hex 或 github 上即可。

您还可以在项目中同时使用 erlang 和 elixir 代码,如 here 所述。

所以是的,完全可以从 elixir 中调用 erlang 代码。

反之亦然,更多信息请参阅here:

Elixir 编译成 BEAM 字节码(通过 Erlang 抽象格式)。这 意味着可以从 Erlang 调用 Elixir 代码,反之亦然, 无需编写任何绑定。

【讨论】:

另外,如原始问题中所问,Code.eval_string/3: Code.eval_string(":rand.uniform(100)") #⇒ 38, [] 优秀。感谢您指向我的文档。 接受是因为参考了文档,但也请参阅@Hauleth 的答案,其中有很好的例子。

以上是关于Erlang 源代码可以嵌入到 Elixir 代码中吗?如果是这样,怎么做?的主要内容,如果未能解决你的问题,请参考以下文章

Docker 上的 Erlang/Elixir 和热代码交换

使用 Erlang 的 Elixir 模块失败

E1.获取Elixir/Erlang版本信息

Elixir Enum vs Erlang列表

Elixir重命名并包装Erlang模块?

Erlang之父学习Elixir语言的一周