module - Lua 意大利面条模块

标签 module lua modularity readability code-readability

我目前正在开发自己的编程语言。代码库(在 Lua 中)由几个模块组成,如下所示:

  • 第一个,error.lua,没有依赖;
  • lexer.lua只依赖于error.lua;
  • prototypes.lua 也没有依赖;
  • parser.lua,而是依赖于上述所有模块;
  • interpreter.lua 是整个代码库的支点。依赖error.lua、parser.lua、memory.lua;
  • memory.lua依赖于functions.lua;
  • 最后,functions.lua依赖memory.lua和interpreter.lua。它是从 memory.lua 内部需要的,所以我们可以说 memory.lua 也依赖于 interpreter.lua。

“A 依赖于 B”是指 A 中声明的函数需要 B 中声明的函数。

不过,真正的问题是当 A 依赖于 B 而 B 又依赖于 A 时,正如您从上面的列表中所理解的那样,这种情况在我的代码中经常发生。

举一个具体的例子来说明我的问题,这里是 interpreter.lua 的样子:

--first, I require the modules that DON'T depend on interpreter.lua
local parser, Error = table.unpack(require("parser"))
--(since error.lua is needed both in the lexer, parser and interpreter module,
--I only actually require it once in lexer.lua and then pass its result around)

--Then, I should require memory.lua. But since memory.lua and
--functions.lua need some functions from interpreter.lua to work, I just
--forward declare the variables needed from those functions and then those functions themself:

--forward declaration
local globals, new_memory, my_nil, interpret_statement

--functions I need to declare before requiring memory.lua
local function interpret_block()
    --uses interpret_statement and new_memory
end
local function interpret_expresion()
    --uses new_memory, Error and my_nil
end

--Now I can safely require memory.lua:
globals, new_memory, my_nil = require("memory.lua")(interpret_block, interpret_espression)
--(I'll explain why it returns a function to call later)

--Then I have to fulfill the forward declaration of interpret_executement:
function interpret_executement()
    --uses interpret_expression, new_memory and Error
end

--finally, the result is a function
return function()
    --uses parser, new_fuction and globals
end

memory.lua 模块返回一个函数,以便它可以接收 interpret_blockinterpret_expression 作为参数,如下所示:

--memory.lua
return function(interpret_block, interpret_expression)
    --declaration of globals, new_memory, my_nil
    return globals, new_memory, my_nil
end

现在,我了解了前向声明 here以及作为模块的函数(就像在 memory.lua 中,将一些函数从需要的模块传递到需要的模块)here .它们都是很棒的想法,我必须说它们非常有效。但是你付出了可读性的代价。

事实上,这次将代码分成更小的部分让我的工作更加努力,如果我将所有内容都编码在一个文件中,这对我来说是不可能的,因为它超过 1000 行代码而且我正在编码来自智能手机。

我的感觉是使用意大利面条代码,只是规模更大。

那么我该如何解决我的代码因为一些模块需要彼此工作而无法理解的问题(当然,这不涉及将所有变量设为全局变量)?其他语言的程序员将如何解决这个问题?我应该如何重组我的模块?使用 Lua 模块是否有任何标准规则也可以帮助我解决这个问题?

最佳答案

如果我们将您的 lua 文件视为有向图,其中顶点从依赖项指向其用法,目标是将您的图修改为树或森林,因为您打算摆脱循环。

环是一组节点,沿顶点方向遍历可以到达起始节点。

现在,问题是如何摆脱循环?

答案是这样的:

让我们考虑节点 N 并将 {D1, D2, ..., Dm} 视为其直接依赖项。如果该集合中没有直接或间接依赖于 N 的 Di,那么您可以让 N 保持原样。在这种情况下,有问题的依赖项集如下所示:{}

但是,如果您有一个非空集,例如:{PD1, ..., PDk} 怎么办?

然后您需要分析 1 和 k 之间的 i 以及 N 的 PDi,看看每个 PDi 中不依赖于 N 的子集是什么,N 的子集是什么不依赖于任何 PDi。这样你就可以定义 N_base 和 N,PDi_base 和 PDi。 N 依赖于 N_base,就像所有 PDi 元素一样,PDi 依赖于 PDi_base 和 N_base。

这种方法最小化了依赖树中的圆圈。但是,很可能这个组中存在 {f1, ..., fl} 的函数集,由于依赖关系而无法迁移到 _base 中,并且仍然存在循环。在这种情况下,您需要为相关组命名,为其创建一个模块并将所有函数迁移到该组中。

关于module - Lua 意大利面条模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39073311/

相关文章:

python - 无法使用 easy_install 安装 Python 模块

javascript - 对 CommonJS 配置文件使用全局变量

nginx - 记录由 nginx 的 Lua 模块设置的变量

java - OSGi Bundle 无法自动解析

jsf - 将 JSF 复合组件打包到 JAR 中

php - zend框架中没有冗余的模块化结构(不相互依赖)

Python 无法放置模块

javascript - 在 NodeJ 中组合不同的模块

c++ - 如何让lua调用一个返回多个值给lua的c++函数

for-loop - lua for 循环使用