Functions in data structures
Fredrik Linder
fredrik.linder@REDACTED
Tue Jun 17 13:06:26 CEST 2003
Thank you!
This was very informative, and as you said, this IS groovy. :-)
/Fredrik
> -----Original Message-----
> From: owner-erlang-questions@REDACTED
> [mailto:owner-erlang-questions@REDACTED]On Behalf Of Luke Gorrie
> Sent: den 17 juni 2003 12:30
> To: Fredrik Linder
> Cc: Erlang Questions
> Subject: Re: Functions in data structures
>
>
> "Fredrik Linder" <fredrik.linder@REDACTED> writes:
>
> > -- ZIP --
> > > There is another option, seldomly exercized: you can send an
> > > abstract form and evaluate it on the other side. This is
> > > more stable in time and space than the other option, but
> > > at the cost of slightly worse performance. The performance
> > > issue can be partly overcome by on-the-fly compilation.
> > >
> > > /Uffe
> >
> > Interesting, is that implemented within Erlang? And if so,
> where can I read
> > about it/how to use it?
>
> Consider this shell fragment:
>
> (x@REDACTED)1> Node = node().
> x@REDACTED
> (x@REDACTED)2> F = fun() -> {fun_created_on, Node} end.
> #Fun<erl_eval.19.280769>
>
> The last return value, #Fun<erl_eval.19.280769>, is not a fun created
> directly from the expression {fun_created_on, Node}. Instead, the fun
> was created in erl_eval, and it captures the current variable bindings
> and the syntax-tree of the code it's actually supposed to run
> (i.e. {fun_created_on, Node}).
>
> Here is the bit of erl_eval that creates the fun:
>
> 1. expr({'fun',Line,{clauses,Cs}}, Bs, Lf) ->
> 2. %% This is a really ugly hack!
> 3. case length(element(3,hd(Cs))) of
> 4. 0 -> {value,fun () -> eval_fun(Cs, [], Bs, Lf) end,Bs};
>
> If you actually call the fun:
>
> (x@REDACTED)3> F().
> {fun_created_on,x@REDACTED}
>
> The code it executes is actually the eval_fun(...) from line (4)
> above. This then *interprets* the {fun_created_on, Node} expression,
> which was captured in the erl_eval fun along with the set of variable
> bindings.
>
> Very groovy!
>
> The nice part is that, so long as two nodes have compatible copies of
> erl_eval, they will always be able to run each others' code in this
> way.
>
> BTW, here is a code snippet out of Distel's backend which uses
> erl_eval directly:
>
> eval_expression(S) ->
> case parse_expr(S) of
> {ok, Parse} ->
> try_evaluation(Parse);
> {error, {_, erl_parse, Err}} ->
> {error, Err}
> end.
>
> try_evaluation(Parse) ->
> case catch erl_eval:exprs(Parse, []) of
> {value, V, _} ->
> {ok, flatten(io_lib:format("~p", [V]))};
> {'EXIT', Reason} ->
> {error, Reason}
> end.
>
> parse_expr(S) ->
> {ok, Scan, _} = erl_scan:string(S),
> erl_parse:parse_exprs(Scan).
>
> Using that, you can create "portable" funs in your programs, like
> this:
>
> 1> distel:eval_expression("fun() -> hello() end.").
> {ok,"#Fun<erl_eval.19.280769>"}
>
> Although if you want the funs to include variable bindings, you'll
> need to pass them as a key-value list to that call to erl_eval:exprs,
> where I just use the empty list.
>
> Cheers,
> Luke
>
>
More information about the erlang-questions
mailing list