如何通过 Erlang 的预处理器有条件地排除整个子句?
How to conditionally exclude whole clauses via Erlang's preprocessor?
我正在用 Erlang 编写一些模块,应该在各种 OTP 版本上编译。在某些情况下,我想使用旧版本中不受支持的 ++
运算符模式,但前提是它可用。因此,我对这项任务的尝试如下:
f([]) -> empty;
f([_|_]) -> cons;
-if(?OTP_RELEASE >= 23).
f([] ++ _) -> empty_append;
-endif.
f(X) -> error(nah).
我找到的解决此问题的方法是:
将 iffed 子句移到开头。然而,这在以下情况下效果不佳:
- 我需要添加更多
-if
s
- 条款的顺序禁止我出于任何原因这样做。
创建一个美丽的ifelses花园,整个功能复制了几次。很显然,这样是不行的。
有什么方便的方法吗?如果可能的话,我会很感激一个通用的解决方案,不限于目前的情况。
来自flow control in macros:
The macro directives cannot be used inside functions.
所以如果你想使用-ifdef
你需要复制多次相同的功能。
(我想这与它们被定义在 -
和 .
之间有关)
话虽如此,您可以执行以下操作:
f([]) -> empty;
f([_|_]) -> cons;
f([] ++ _) when ?OTP_RELEASE >= 23 -> empty_append;
f(X) -> error(nah).
您可以使用 erlc -S <module>
验证永远不会匹配的子句已从生成的 beam ASM 代码中删除。此外,编译器将显示警告。
这一步产生的警告不能选择性省略。来自 here:
Another class of warnings is generated by the compiler during optimization and code generation. They warn about patterns that will never match (such as a=b), guards that always evaluate to false, and expressions that always fail (such as atom+42).
Those warnings cannot be disabled (except by disabling all warnings).
如果你想完全避免警告,你需要类似的东西(请注意,这种风格不会删除分支,因为 OtpRelease
是一个变量):
f(Term) ->
f(Term, ?OTP_RELEASE).
f([], _) -> empty;
f([_|_], _) -> cons;
f([] ++ _, OtpRelease) when OtpRelease >= 23 -> empty_append;
f(_, _) -> error(nah).
编辑:
在最后一个示例中,OTP23 的代码优化器能够删除无法访问的代码。在这种特殊情况下,如果 f/2
未导出,则根据 ?OTP_RELEASE
)
将删除其第 3 或第 4 个子句
我正在用 Erlang 编写一些模块,应该在各种 OTP 版本上编译。在某些情况下,我想使用旧版本中不受支持的 ++
运算符模式,但前提是它可用。因此,我对这项任务的尝试如下:
f([]) -> empty;
f([_|_]) -> cons;
-if(?OTP_RELEASE >= 23).
f([] ++ _) -> empty_append;
-endif.
f(X) -> error(nah).
我找到的解决此问题的方法是:
将 iffed 子句移到开头。然而,这在以下情况下效果不佳:
- 我需要添加更多
-if
s - 条款的顺序禁止我出于任何原因这样做。
- 我需要添加更多
创建一个美丽的ifelses花园,整个功能复制了几次。很显然,这样是不行的。
有什么方便的方法吗?如果可能的话,我会很感激一个通用的解决方案,不限于目前的情况。
来自flow control in macros:
The macro directives cannot be used inside functions.
所以如果你想使用-ifdef
你需要复制多次相同的功能。
(我想这与它们被定义在 -
和 .
之间有关)
话虽如此,您可以执行以下操作:
f([]) -> empty;
f([_|_]) -> cons;
f([] ++ _) when ?OTP_RELEASE >= 23 -> empty_append;
f(X) -> error(nah).
您可以使用 erlc -S <module>
验证永远不会匹配的子句已从生成的 beam ASM 代码中删除。此外,编译器将显示警告。
这一步产生的警告不能选择性省略。来自 here:
Another class of warnings is generated by the compiler during optimization and code generation. They warn about patterns that will never match (such as a=b), guards that always evaluate to false, and expressions that always fail (such as atom+42).
Those warnings cannot be disabled (except by disabling all warnings).
如果你想完全避免警告,你需要类似的东西(请注意,这种风格不会删除分支,因为 ): OtpRelease
是一个变量
f(Term) ->
f(Term, ?OTP_RELEASE).
f([], _) -> empty;
f([_|_], _) -> cons;
f([] ++ _, OtpRelease) when OtpRelease >= 23 -> empty_append;
f(_, _) -> error(nah).
编辑:
在最后一个示例中,OTP23 的代码优化器能够删除无法访问的代码。在这种特殊情况下,如果 f/2
未导出,则根据 ?OTP_RELEASE
)