Erlang:用新功能“扩展”现有模块

Posted

技术标签:

【中文标题】Erlang:用新功能“扩展”现有模块【英文标题】:Erlang: "extending" an existing module with new functions 【发布时间】:2011-09-25 16:26:55 【问题描述】:

我目前正在编写一些与我可能重用的列表相关的函数。

我的问题是:

是否有组织此类功能的约定或最佳实践?

为了解决这个问题,理想情况下,我想“扩展”现有的列表模块,这样我就可以通过以下方式调用我的新函数:lists:my_funcion()。目前我有lists_extensions:my_function()。有没有办法做到这一点?

我读到了 erlang 包,它们本质上是 Erlang 中的命名空间。是否可以使用新的 Lists 函数为 Lists 定义新的命名空间?

请注意,我不是要分叉和更改标准列表模块,而是要找到一种方法在也称为列表的新模块中定义新函数,但通过使用某种命名空间方案来避免随之而来的命名冲突。

任何建议或参考将不胜感激。

干杯。

【问题讨论】:

听起来并不滑稽,但它是开源的。您可以分叉存储库并将您的更改添加到列表模块? 你可以。问题是你不能分发你自己的源代码而不必修补 Erlang/OTP。不是一个理想的解决方案。 我认为,当我们说扩展 erlang 模块时,我们的意思是添加更多功能或更改现有功能。我认为“adamstantonvan”想要的只是添加他的个人功能,以便从 lists.erl 中调用 抱歉,我的问题不太清楚。刚刚更新了问题以澄清我不打算分叉和更改,只是为了创建另一个同名的模块但避免命名冲突。 为什么需要这样做?幸运的是,我们不再像过去那样在模块名称中绑定 6 个字符,因此您可以组成很多名称。除了您可能想要访问的 Erlang 模块中的私有函数(没有实例变量、没有继承)之外,没有其他任何东西。 【参考方案1】:

为了解决这个问题,理想情况下,我想“扩展”现有的列表模块,这样我就可以通过以下方式调用我的新函数:lists:my_funcion()。目前我有lists_extensions:my_function()。有没有办法做到这一点?

没有,据我所知。

我读到了 erlang 包,它们本质上是 Erlang 中的命名空间。是否可以使用新的 Lists 函数为 Lists 定义一个新的命名空间?

他们是experimental and not generally used。您可以在不同的命名空间中拥有一个名为 lists 的模块,但在从该命名空间中的标准模块调用函数时会遇到问题。

【讨论】:

据我所知,Erlang中没有解决方案。 Ocaml 和 Standard ML 有一个漂亮的解决方案,它基于在新命名空间中包含签名和打开模块。但对于 Erlang 来说,这是一个行不通的解决方案。【参考方案2】:

我猜你想要做的是让你的一些函数可以从列表模块中访问。最好将常用代码转换为库。

一种方法是测试你的函数,如果它们没问题,你复制函数,将它们粘贴到lists.erl模块中(警告:确保你没有覆盖现有的函数,只需粘贴在文件末尾)。此文件可以在路径 $ERLANG_INSTALLATION_FOLDER/lib/stdlib-$VERSION/src/lists.erl 中找到。确保将您的函数添加到列表模块(在-export([your_function/1,.....]))中导出的函数中,以使它们可以从其他模块访问。保存文件。

完成此操作后,我们需要重新编译列表模块。您可以使用EmakeFile。该文件的内容如下:

“src/*”,[详细,报告,strict_record_tests,warn_obsolete_guard,outdir,“ebin”]。

将该文本复制到名为 EmakeFile 的文件中。将此文件放在路径中:$ERLANG_INSTALLATION_FOLDER/lib/stdlib-$VERSION/EmakeFile

完成后,打开一个erlang shell,让它的pwd(),当前工作目录为EmakeFile所在的路径,即$ERLANG_INSTALLATION_FOLDER/lib/stdlib-$VERSION/ b>.

在shell中调用函数:make:all(),你会看到模块列表被重新编译。关闭外壳。

一旦你打开一个新的 erlang shell,并假设你在列表模块中导出了你的函数,它们就会按照你想要的方式运行,就在列表模块中。 Erlang 是开源的,允许我们添加功能、重新编译和重新加载库。这应该做你想要的,成功。

【讨论】:

这会起作用,但它确实会改变基本模块。我认为这个问题的框架是暗示你是否可以对现有模块进行猴子补丁。【参考方案3】:

我告诉你为什么使用lists:your_function(),而是使用lists_extension:your_function()

通常,Erlang/OTP 设计指南规定每个“应用程序”——库也是一个应用程序——都包含模块。现在你可以问系统what application did introduce a specific module?这个系统会在模块碎片化时崩溃。

不过,我确实理解您为什么想要lists:your_function/N

your_function 的作者使用起来更方便,因为他在使用[] 时非常需要your_function(...)当另一个 Erlang 程序员——知道stdlb——读到这段代码时,他不会知道它做了什么。这令人困惑。 它看起来比lists_extension:your_function/N 更简洁。 这是一个品味问题。

【讨论】:

【参考方案4】:

我认为这种方法适用于任何发行版:

您可以创建一个应用程序,自动重写正在运行的任何发行版的核心 erlang 模块。将您的自定义函数附加到核心模块并重新编译它们,然后编译和运行您自己的调用自定义函数的应用程序。这不需要自定义分发。只是一些仔细规划和使用文件工具和 BIF 来编译和加载。 * 你要确保你不会每次都附加你的函数。重写文件后,它将是永久性的,除非用户稍后替换该文件。可以使用 module_info 检查来确认您的自定义函数是否存在,以决定您是否需要运行扩展编写器。

伪例子:

lists_funs() -> ["myFun() -> <<"things to do">>."].
extend_lists() -> 
   ok, Io = file:open(?LISTS_MODULE_PATH, [append]),
   lists:foreach(fun(Fun) -> io:format(Io,"~s~n",[Fun]) end, lists_funs()),
   file:close(Io),
   c(?LISTS_MODULE_PATH).

* 如果编译器失败,您可能希望保留原始模块的副本以进行恢复重写模块以使用更多功能对其进行扩展。 * 您可以使用 list_extension 模块来保留函数的所有逻辑,并使用 funName(Args) -&gt; lists_extension:funName(Args). 将函数传递到此函数中的列表 * 你也可以创建一个覆盖系统来搜索现有函数并以类似的方式重写它们,但它更复杂。 我确信有很多方法可以改进和优化这种方法。我使用类似的东西在运行时更新我自己的一些模块,所以我看不出有任何理由它也不能在核心模块上工作。

【讨论】:

以上是关于Erlang:用新功能“扩展”现有模块的主要内容,如果未能解决你的问题,请参考以下文章

用erlang解析ejabberd数据包

使用通用测试的模块的 Erlang 测试(非导出/私有)功能

SpaceVim 语言模块 erlang

手动功能模块传输到另一个系统现有功能组?

如何在erlang中应用热代码交换功能作为补丁?

面向对象七大原则