[erlang-questions] escript question

Ulf Wiger ulf.wiger@REDACTED
Mon Sep 19 16:37:53 CEST 2011


On 19 Sep 2011, at 16:22, Garrett Smith wrote:

> 
> E.g. store a function in your database that increments a number by 1:
> 
> FStr = "fun(N) -> N + 1 end."
> 
> When you're ready to use it:
> 
> {ok, Tokens, _} = erl_scan:string(FStr),
> {ok, Exprs} = erl_parse:parse_exprs(Tokens),
> {value, F, []} = erl_eval:exprs(Exprs, []).
> 
> Now:
> 
> 2 = F(1).

I'd go one step further and store Exprs in the database directly, eliminating the parsing step.

To avoid having to learn the abstract form representation, you can use parse_trans_codegen.erl.

http://github.com/esl/parse_trans

Example:

-module(storefun).
-export([f/1]).

-include_lib("parse_trans/include/codegen.hrl").

f(1) ->
    codegen:exprs(fun() ->
			  fun(N) ->
				  N + 1
			  end
		  end).

Compiling this with parse_trans/ebin in the path:

Eshell V5.8.4  (abort with ^G)
1> c(storefun).
{ok,storefun}
2> storefun:f(1).
[{'fun',8,
        {clauses,[{clause,8,
                          [{var,8,'N'}],
                          [],
                          [{op,9,'+',{var,9,'N'},{integer,9,1}}]}]}}]
3> {value, F, []} = erl_eval:exprs(v(2),[]).
{value,#Fun<erl_eval.6.13229925>,[]}
4> F(2).
3

That is, codegen:exprs(fun() -> <Exprs> end) returns the abstract form list for <Exprs>. If you want the expressions to inherit variables, you can do that  by defining those variables as arguments to the enclosing fun:

f(2) ->
    codegen:exprs(fun(X) ->
			  fun(N) ->
				  N + X
			  end
		  end).


5> c(storefun).                             
{ok,storefun}
6> storefun:f(2).                           
[{'fun',14,
        {clauses,[{clause,14,
                          [{var,14,'N'}],
                          [],
                          [{op,15,'+',{var,15,'N'},{var,15,'X'}}]}]}}]
7> {value, F2, []} = erl_eval:exprs(v(6),[]).
** exception error: {unbound_var,'X'}
8> {value, F2, []} = erl_eval:exprs(v(6),[{'X',17}]).
** exception error: no match of right hand side value 
                    {value,#Fun<erl_eval.6.13229925>,[{'X',17}]}
9> {value, F2, _} = erl_eval:exprs(v(6),[{'X',17}]). 
{value,#Fun<erl_eval.6.13229925>,[{'X',17}]}
10> F2(3).
20


The abstract code is generated at compile-time, so there is very little overhead.

BR,
Ulf W

Ulf Wiger, CTO, Erlang Solutions, Ltd.
http://erlang-solutions.com






More information about the erlang-questions mailing list