Binding value in LFE interpreter using Erlang
I would like to use Lisp Flavored Erlang as a scripting extension language for an Erlang application . If you want, GNU Emacs is similarly customized and extended via Emacs Lisp .
I know the argument is broad and structured; but for the specific case of this question, I would like to read the binding name (or variable if you like) defined in the LFE from Erlang code.
I'm not an LFE internal architecture expert (which is a great example of software development and Erlang programming), but I couldn't find an answer either in the sources or in the documentation. Looking at sources I see that the LFE contains both a compiler targeting the Erlang VM and an interpreter... The last one is the one I'm trying to use.
If I run the Erlang / REPL wrapper in the LFE install path (on my system $HOME/opt/lfe
):
$ cd /path/to/LFE-install-dir
$ erl -pa ./ebin
I can calculate the value:
1> {ok, Expr} = lfe_io:read_string("(+ 1 10)").
{ok,['+',1,10]}
2> Result = lfe_eval:expr(Expr).
11
This is the first step, but not exactly what I want. I would rather bind a variable and read its value; that's my problem:
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
Why is it set
recognized as an unbound function? In the LFE REPL, this expression is valid:
Erlang / OTP 17 [erts-6.4] [source] [64-bit] [smp: 4: 4] ... LFE Shell V6.4 (abort with ^ G) > (set a 10) ten > a ten
I am obviously using the API incorrectly. How can I read the content a
and / or initialize the LFE interpreter correctly ?
(If explained somewhere, please include a link).
source to share
I will not attempt to fully answer your broader question about "best practices" for adding scripts. It seems to me that the choice is between a "hook based" solution (in which you define hook implementations by naming convention and they are automatically recognized) and an "explicit api" solution (in which you use functions predefined in the scripting environment to register your hooks or otherwise called configuration functions) is highly dependent on taste. Explicit calls such as (set-connection-timeout-handler ...) can be more readable, easier to debug (no spelling issues, no surprises on api changes), easier to document, and a little more flexible, but more explicit.
Based on a simple example of defining variables, here are a few ways in which one could continue the path "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
source to share