Elixir函数get_horizontal_line重求值场景及Erlang VM学习资源咨询
关于你提出的两个问题,解答如下:
问题1:get_horizontal_line 函数的求值场景
首先需要纠正你代码注释里的一个常见误解:Elixir 是严格求值语言,不存在「绑定函数调用结果但不执行计算」的逻辑。你写的x = get_horizontal_line()在执行到赋值语句时,函数就已经完成计算,x绑定的是已经生成好的字符串,不是待执行的函数引用。
对应的你示例代码里的执行逻辑是:
def get_horizontal_line, do: String.duplicate("-", 80) def get_horizontal_line(n), do: String.duplicate("-", n) # 这里已经执行了一次get_horizontal_line(),x绑定计算完成的字符串 x = get_horizontal_line() # 这里第二次执行get_horizontal_line(),y绑定新生成的字符串 y = get_horizontal_line() # 直接输出x绑定的已有值,不会触发函数求值 IO.puts(x) # 直接输出y绑定的已有值,不会触发函数求值 IO.puts(y) # 这里执行第一次get_horizontal_line(80) x = get_horizontal_line(80) # 这里执行第二次get_horizontal_line(80) y = get_horizontal_line(80) # 同样是输出已有绑定值,无函数调用 IO.puts(x) IO.puts(y)
这个函数会被重新求值的场景只有一种:你显式调用它的时候。Elixir默认不会对纯函数做自动缓存,哪怕两次调用传入的参数完全一致,每次调用都会重新执行一次逻辑。少数情况下编译器会对无副作用的公共子表达式做消除优化,但这属于编译器的可选优化行为,不要依赖这个特性来避免重复计算。
如果需要避免重复执行,直接把函数返回值绑定到变量复用即可。
问题2:Erlang VM与编译器学习推荐路径
你当前的学习顺序(Elixir文档→Erlang文档→VM相关知识)非常合理,在动手读BEAM源码之前,可以按以下路径补充前置知识:
- 先通读《Erlang编程指南》中运行时相关的章节,先建立对BEAM基础设计理念的认知,包括进程模型、内存管理、调度器核心逻辑、消息传递的底层规则
- 再看《Erlang/OTP并发编程实战》中涉及底层执行逻辑的部分,理解OTP组件和VM的交互逻辑,知道上层API对应到VM层面的操作是什么
- 编译器相关可以先从Erlang官方文档中的编译选项说明、BEAM字节码规范入手,搞清楚从源文件到.beam字节码的完整编译流程,每个阶段的处理逻辑
- VM架构部分可以先看社区整理的BEAM内部原理相关的资料,搞清楚BEAM的寄存器设计、GC实现、进程调度策略、异常处理逻辑这些核心模块的设计,再去读源码效率会高很多
- 可以自己写简单的示例代码,编译成BEAM字节码后对照指令说明逐行分析,能快速建立对VM执行逻辑的直观认知
内容的提问来源于stack exchange,提问作者cppProgrammer
相关产品推荐
相关产品推荐

