使用 Erlang 在 LFE 解释器中绑定的值

Value from binding in LFE interpreter using Erlang

我想使用 Lisp Flavored Erlang 作为 脚本扩展语言 Erlang 应用程序。 如果你愿意,以类似的方式 GNU Emacs is configured and extended via Emacs Lisp.

我知道这个论点广泛而有条理;但在这个问题的特定情况下,我希望能够从 Erlang 代码中读取 LFE 中定义的 绑定名称(或变量,如果你愿意的话)。

我不是 LFE 内部架构专家(这是软件工程和 Erlang 编程的一个很好的例子),但我没能找到来源和文档中都没有答案。 查看 sources I can see that LFE contains both a compiler that target Erlang VM 解释器 。 后者是我正在尝试使用的那个。

如果我在 LFE 安装路径中启动 Erlang shell/REPL(在我的系统 $HOME/opt/lfe 上):


$ cd /path/to/LFE-install-dir
$ erl -pa ./ebin

我可以计算出一个值:


1> {ok, Expr} = lfe_io:read_string("(+ 1 10)").
{ok,['+',1,10]}
2> Result = lfe_eval:expr(Expr).
11

这是第一步,但不是我想要的。我宁愿绑定一个变量并读取它的值;那是我的问题:


3> {ok, Expr2} = lfe_io:read_string("(set a 10)").
{ok,[set,a,10]}
4> lfe_eval:expr(Expr2).
** exception error: {unbound_func,{set,2}}
     in function  lfe_eval:eval_expr/2

为什么set被识别为未绑定函数?在 LFE REPL 中,此表达式有效:

Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:4:4] ...
LFE Shell V6.4 (abort with ^G)
> (set a 10)
10
> a
10

我显然用错了API。我如何读取a的内容and/or正确初始化LFE 解释器?

(如有解释请提供参考)

我不会尝试完全回答您关于 "best practices" 添加脚本的更广泛的问题。在我看来,在 "hook-based" 解决方案(您通过名称约定定义钩子实现并且它们被自动识别)和 "explicit api" 解决方案(您使用脚本环境中预定义的函数来注册您的挂钩或以其他方式调用配置函数)在很大程度上是个人喜好问题。像 (set-connection-timeout-handler ...) 这样的显式调用可能更具可读性,更容易调试(没有拼写错误问题,api 更改没有意外),更容易记录,也更灵活,但更多,嗯,明确。

根据您的简单变量定义示例,您可以通过以下几种方式开始进一步 "interpreted" 路径:

1> {ok, Expr} = lfe_io:read_string("'((a 10))").
{ok,[quote,[[a,10]]]}
2> lfe_eval:expr (Expr).
[[a,10]]

3> EvalAll = fun (Conf) -> {ok, E} = lfe_io:read_string("'(" ++ Conf ++ ")"), lfe_eval:expr(E) end.
#Fun<erl_eval.6.90072148>
4> EvalAll ("(a 10) (b 11)").                                                                      
[[a,10],[b,11]]

5> EvalAllL = fun (Conf) -> {ok, E} = lfe_io:read_string("(list " ++ Conf ++ ")"), lfe_eval:expr(E) end.
#Fun<erl_eval.6.90072148>
6> [{f, F}] = EvalAllL ("(tuple 'f (lambda (x) (+ 10 x)))").
[{f,#Fun<lfe_eval.12.2018457>}]
7> F (12).
22

8> G = fun (X) -> X * 2 end.
#Fun<erl_eval.6.90072148>
9> lfe_eval:expr (element (2, lfe_io:read_string ("(g 15)")), lfe_eval:add_lexical_func(g, 1, G, lfe_env:new ())).
30

一个简单的方法是使用 'lfe' 命令到 运行 LFE 脚本。 'lfe' 的行为方式与 'bash' 相似,因为您可以将它用于 运行 脚本。 bin/lfec 中定义的 'lfec' 脚本就是一个很好的例子。它是一个 LFE shell 脚本,它解析它的参数和 运行 LFE 编译器。